Usercontrol 中带有 CompositeCollection 的 WPF ComboBox 不起作用:SelectedIndex 设置为 -1
WPF ComboBox with CompositeCollection in Usercontrol does not work: SelectedIndex set to -1
我正在使用 MVVM。
我有一个由
组成的 CompositeCollection
- 以 'Select a vendor' 为内容的 ComboboxItem
- 有界的 CollectionContainer
当我直接在我的视图中使用 ComboBox XAML 代码时,SelectedIndex 设置为 0(如预期的那样)。
但是,当我将 ComboBox XAML 代码放入 Usercontrol 并在我的视图中使用该控件时,SelectedIndex 设置为 -1。
知道如何解决这个问题,以便我可以使用用户控件吗?
我的所有绑定都有效。
注:
- 当 Combobox XAML 代码直接在视图中时:当用户选择 'Select a vendor' 时,ComboboxConverter 将 Vendor 属性 设置为 null。
但是,当 ComboBox XAML 代码位于 Usercontrol 中时,代码不会进入
if (comboboxItem.Content.ToString() == "Select a vendor")
{
//gets here when code is in view <-> code in control
return null;
}
组合框转换器
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;
}
}
供应商控制
<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));
});
}
开始时,当您的 Vendor 为 null 时,函数 Convert 也会 return null 但您的组合框不知道 null 是什么意思,这就是为什么它将其 selected 索引值设置为 - 1.
您可以通过创建一个行为来解决此问题,该行为在设置为 -1 时始终 select 索引 0。
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;
}
}
}
然后在你的 XAML 部分:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
...
在您的组合框中:
<i:Interaction.Behaviors>
<SelectFirstItemBehavior/>
</i:Interaction.Behaviors>
我正在使用 MVVM。
我有一个由
组成的 CompositeCollection- 以 'Select a vendor' 为内容的 ComboboxItem
- 有界的 CollectionContainer
当我直接在我的视图中使用 ComboBox XAML 代码时,SelectedIndex 设置为 0(如预期的那样)。
但是,当我将 ComboBox XAML 代码放入 Usercontrol 并在我的视图中使用该控件时,SelectedIndex 设置为 -1。 知道如何解决这个问题,以便我可以使用用户控件吗?
我的所有绑定都有效。
注:
- 当 Combobox XAML 代码直接在视图中时:当用户选择 'Select a vendor' 时,ComboboxConverter 将 Vendor 属性 设置为 null。
但是,当 ComboBox XAML 代码位于 Usercontrol 中时,代码不会进入
if (comboboxItem.Content.ToString() == "Select a vendor")
{
//gets here when code is in view <-> code in control
return null;
}
组合框转换器
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;
}
}
供应商控制
<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));
});
}
开始时,当您的 Vendor 为 null 时,函数 Convert 也会 return null 但您的组合框不知道 null 是什么意思,这就是为什么它将其 selected 索引值设置为 - 1. 您可以通过创建一个行为来解决此问题,该行为在设置为 -1 时始终 select 索引 0。
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;
}
}
}
然后在你的 XAML 部分:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
...
在您的组合框中:
<i:Interaction.Behaviors>
<SelectFirstItemBehavior/>
</i:Interaction.Behaviors>