Supposons que nous ayons un lien DataSource vers une collection de Database. Il n'y a pas d'élément null bien sûr. Comment ajouter un élément void dans une ComboBox , de sorte que, lors du premier chargement, l’utilisateur verrait une chaîne vide. Je ne veux pas ajouter d'objet factice/vide dans la collection. Optimalement en XAML . Des propositions?
<ComboBox Name="myComboBox" Width="200" Background="White">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem IsEnabled="False" Foreground="Black">Select Item</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource DataKey}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
MODIFIER
Comme @surfen mentionné dans le commentaire, BindingProxy est une solution de contournement pour la question contraignante
<UserControl.Resources>
<CollectionViewSource x:Key="Modules" Source="{Binding Path=Modules}" />
</UserControl.Resources>
<abv:ComboBox SelectedIndex="0" IsNullable="True"
SelectedItem="{Binding Path=SelectedModule, Mode=TwoWay}">
<abv:ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Content="{DynamicResource EmptyModuleComboBox}"/>
<CollectionContainer Collection="{Binding Source={StaticResource Modules}}" />
</CompositeCollection>
</abv:ComboBox.ItemsSource>
</abv:ComboBox>
public class ComboBox : System.Windows.Controls.ComboBox
{
public static readonly DependencyProperty IsNullableProperty =
DependencyProperty.Register("IsNullable", typeof(bool), typeof(ComboBox));
public bool IsNullable
{
get { return (bool)GetValue(IsNullableProperty); }
set { SetValue(IsNullableProperty, value); }
}
public ComboBox()
{
Loaded += ComboBox_Loaded;
}
void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
if (IsNullable)
{
this.ItemContainerStyle = new Style();
this.ItemContainerStyle.Setters.Add(new EventSetter()
{
Event = ComboBoxItem.PreviewMouseUpEvent,
Handler = new MouseButtonEventHandler(cmbItem_PreviewMouseUp)
});
}
}
public void cmbItem_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (Items.IndexOf(sender as ComboBoxItem) == 0)
{
SelectedItem = null;
}
}
}
Pour la liaison sur un objet MVVM:
<ComboBox Name="cbbFiltres" SelectedItem="{Binding ElmtInfo, Mode=TwoWay}" Height="26" MinWidth="90" SelectedIndex="0" SelectedValuePath="Id">
<ComboBox.Resources>
<CollectionViewSource x:Key="cvsFiltres" Source="{Binding Elmts.items}"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<model:tblFiltreChamps Desc="{x:Static resx:resMain.enumAucun}" Id="0"/>
<CollectionContainer Collection="{Binding Source={StaticResource cvsFiltres}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
Et pour lier sur:
<Label Visibility="{Binding Path=SelectedValue, ElementName=cbbFiltres, Converter={StaticResource NullToVisibility}}" />
Et le convertisseur générique:
public class ConvNullToVisibility : IValueConverter {
/// <summary>Convertisseur pour le Get.</summary>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (DesignerProperties.GetIsInDesignMode(new DependencyObject())) return Visibility.Visible; // Pour annuler l'effet dans le designer: http://stackoverflow.com/questions/33401900/wpf-detect-design-mode-in-a-converter
return ((value == null) || (string.IsNullOrEmpty(value.ToString())) || (value.ToString() == "0")) ? Visibility.Collapsed : Visibility.Visible;
}
/// <summary>Convertisseur inverse, pour le Set (Binding).</summary>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value is Visibility) {
return (((Visibility)value) == Visibility.Visible) ? true : false;
} else return false;
}
}
Il est juste important de déclarer SelectedValuePath dans une liste déroulante . :-)