I am using MVVM.
I have a CompositeCollection consisting of
When I use the ComboBox XAML code directly in my view the SelectedIndex is set to 0 (as expected).
However, when I put the ComboBox XAML code in a Usercontrol and use the control in my view, the SelectedIndex is set to -1. Any idea how to fix this issue, so that I can use the usercontrol?
All my bindings work.
Note:
However, when ComboBox XAML code is in a Usercontrol the code does not get in
if (comboboxItem.Content.ToString() == "Select a vendor")
{
//gets here when code is in view <-> code in control
return null;
}
ComboboxConverter
public class ComboboxConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var vendor = value as Vendor;
if (vendor != null)
{
return vendor;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var comboboxItem = value as ComboBoxItem;
if (comboboxItem != null)
{
if (comboboxItem.Content.ToString() == "Select a vendor")
{
//gets here when code is in view <-> code in control
return null;
}
return null;
}
var vendor = value as Vendor;
if (vendor != null)
{
return vendor;
}
return null;
}
}
VendorControl
<UserControl x:Class="Tool.Controls.VendorControl"
xmlns:local="clr-namespace:Tool.Controls"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:objects='clr-namespace:Tool.Objects'
xmlns:converters='clr-namespace:Tool.Converters'
mc:Ignorable="d" >
<UserControl.Resources>
<converters:ComboboxConverter x:Key='ComboboxConverter' />
</UserControl.Resources>
<Grid>
<ComboBox Name='cmbVendor'
SelectedItem='{Binding Vendor, Converter={StaticResource ComboboxConverter}, Mode=TwoWay}'
Grid.Column='1'
IsSynchronizedWithCurrentItem='True'>
<ComboBox.Resources>
<CollectionViewSource x:Key='VendorsCollection'
Source='{Binding Vendors}' />
<DataTemplate DataType='{x:Type objects:Vendor}'>
<StackPanel Orientation='Horizontal'>
<TextBlock Text='{Binding Name}' />
</StackPanel>
</DataTemplate>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Content='Select a vendor' />
<CollectionContainer Collection='{Binding Source={StaticResource VendorsCollection}}' />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
ViewModel
private void OnWindowLoaded()
{
LoadVendors();
}
ObservableCollection<Vendor> _vendors = new ObservableCollection<Vendor>();
public ObservableCollection<Vendor> Vendors
{
get
{
return _vendors;
}
}
private Vendor _vendor;
public Vendor Vendor
{
get
{
return _vendor;
}
set
{
if (value != _vendor)
{
_vendor = value;
RaisePropertyChanged(nameof(Vendor));
}
}
}
private void LoadVendors()
{
var dVendors = VendorHelper.GetVendors();
if (Vendors.Count > 0)
{
DispatcherHelper.CheckBeginInvokeOnUI(() => Vendors.Clear());
}
dVendors.ForEach(dV =>
{
var vendor = new Vendor(dV);
DispatcherHelper.CheckBeginInvokeOnUI(() => Vendors.Add(vendor));
});
}
At the beginning when your Vendor is null, function Convert will return null as well but your combobox does not know what null means, that's why it sets its selected index value to -1. You can solve this by creating a behavior which will always select index 0 when it is set to -1.
public class SelectFirstItemBehavior : Behavior<ComboBox>
{
protected override void OnAttached()
{
AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
}
protected override void OnDetaching()
{
AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
base.OnDetaching();
}
private void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var combobox = sender as ComboBox;
if (combobox != null && combobox.SelectedIndex == -1)
{
combobox.SelectedIndex = 0;
}
}
}
And then in your XAML part:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
...
inside your Combobox:
<i:Interaction.Behaviors>
<SelectFirstItemBehavior/>
</i:Interaction.Behaviors>