使组合框ItemsSource通用在UserControl内部以使其可用于多个类型的集合
我正在应用WPF
应用程序,并且最近遇到了制作可重复使用的要求User Controls
。使组合框ItemsSource通用在UserControl内部以使其可用于多个类型的集合
我有两个User Controls
InputUC
和ComboBoxUC
。两者分别具有Label
和TextBox
和Label
和ComboBox
。我已经通过定义所需的依赖属性成功实现了InputUC
。
我面临的问题是ComboBoxUC
。我在我的应用程序中有一个场景,我必须显示Collection
的Cities
,Customers
,Salesmen
和其他实体在不同的地方。很明显,每个实体将提供不同的属性名称,以DisplayMemberPath
,SelectedValuePath
,SelectedValue
属性和不同类型的Collection
作为ItemsSource
属性ComboBox
。
我在互联网上搜索,但没有找到任何相同的解决方案。
我想要的代码是
ComboBox
控制ComboBoxUC.xaml
<ComboBox Name="valuesComboBox"
Grid.Column="1"
ItemsSource="{Binding ComboBoxItems}"
DisplayMemberPath="{Binding ComboBoxDisplayMemberPath}"
SelectedValuePath="{Binding ComboBoxSelectedValuePath}"
SelectedValue="{Binding ComboBoxValue}"
IsEnabled="{Binding ComboBoxIsEnabled}"
Style="{StaticResource ComboBox-Base}">
</ComboBox>
代码ComboBoxUC
背后ComboBoxUC.xaml.cs
public string ComboBoxLabel
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public bool ComboBoxIsRequired
{
get { return (bool)GetValue(IsRequiredProperty); }
set { SetValue(IsRequiredProperty, value); }
}
public long ComboBoxValue
{
get { return (long)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public bool ComboBoxIsEnabled
{
get { return (bool)GetValue(ValueEnabledProperty); }
set { SetValue(ValueEnabledProperty, value); }
}
public ObservableCollection<CityViewModel> ComboBoxItems
{
get { return (ObservableCollection<CityViewModel>)GetValue(ValueItems); }
set { SetValue(ValueItems, value); }
}
public string ComboBoxDisplayMemberPath
{
get { return GetValue(ValueDisplayMemberPath).ToString(); }
set { SetValue(ValueDisplayMemberPath, value); }
}
public string ComboBoxSelectedValuePath
{
get { return GetValue(ValueSelectedValuePath).ToString(); }
set { SetValue(ValueSelectedValuePath, value); }
}
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("ComboBoxLabel", typeof(string),
typeof(ComboBoxUC), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty IsRequiredProperty = DependencyProperty.Register("ComboBoxIsRequired", typeof(bool),
typeof(ComboBoxUC), new PropertyMetadata(false));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("ComboBoxValue", typeof(long),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public static readonly DependencyProperty ValueEnabledProperty = DependencyProperty.Register("ComboBoxIsEnabled", typeof(bool),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(ObservableCollection<CityViewModel>),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public static readonly DependencyProperty ValueDisplayMemberPath = DependencyProperty.Register("ComboBoxDisplayMemberPath", typeof(string),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public static readonly DependencyProperty ValueSelectedValuePath = DependencyProperty.Register("ComboBoxSelectedValuePath", typeof(string),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public ComboBoxUC()
{
InitializeComponent();
}
从Page
控件的代码,我现在用的这个UserControl
是
<local:ComboBoxUC ComboBoxLabel="City"
ComboBoxIsRequired="True"
ComboBoxValue="{Binding CustomerViewModel.customer_city_id}"
ComboBoxItems="{Binding Cities}"
ComboBoxDisplayMemberPath="city_name"
ComboBoxSelectedValuePath="city_id"
ComboBoxIsEnabled="{Binding Flags.AddOrUpdate}">
</local:ComboBoxUC>
现在我将在我的应用程序的多个地方使用上面的xaml
。 可以在每种情况下而变化的事情是:
- CustomerViewModel.customer_city_id
- 城市
- CITY_NAME
- city_id
我已正确设置在ComboBoxUC.xaml
DataContext
的和当前代码因为我的UserControl
对于一种类型的Collection (CityViewModel)
正常工作。我想为其他实体(如CustomerViewModel
,SalesmanViewModel
等)使用相同的代码,并使用明显不同的属性名称。
我想下面的代码是通用的。
public ObservableCollection<CityViewModel> ComboBoxItems
{
get { return (ObservableCollection<CityViewModel>)GetValue(ValueItems); }
set { SetValue(ValueItems, value); }
}
public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(ObservableCollection<CityViewModel>),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
我已经试过object
型Collection
很好,但当然object
类型没有,我在我的实体的属性。
帮助将被赞赏,因为我被卡住了,并且无法从这一点开始发展。
而不是尝试使用户控件中的集合通过使它们成为泛型来进行强类型化,而应该使它们不那么强类型化;请记住,Combobox的ItemsSource本身就是类型'object'。
我建议你让你的ComboBoxUC公开一个IEnumerable类型的DependencyProperty并将它绑定到ComboBox ItemsSource。然后还公开一个DataTemplate类型的DependencyProperty并将其绑定到ComboBox的ItemTemplate属性。使用用户控件时,可以提供一个简单的DataTemplate来显示所需的属性,而不是使用DisplayMember路径。例如,当你想在ComboboxUC显示市的,你可以这样做:
<local:ComboBoxUC ItemsSource="{Binding Cities}">
<local.ComboBoxUC.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding city_name}"/>
</DataTemplate>
</local:ComboBoxUC.ItemTemplate>
</local:ComboBoxUC/>
然后,我会揭露组合框的的SelectedItem的用户控件的一个DependencyProperty,如果你绝对必须绑定到SelectedValuePath代替SelectedItem的使用ValueConverter。
说实话,感觉这些用户控件有点OTT。如果您所获得的只是标签和样式,则可以通过在资源字典中重新设计控件并将模板应用到要以此方式使用的每个组合框来实现。
需要改变的唯一的事情就是@ibebbs指出的ObservableCollection
到IEnumerable
的类型。
public IEnumerable ComboBoxItems
{
get { return (IEnumerable)GetValue(ValueItems); }
set { SetValue(ValueItems, value); }
}
public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(IEnumerable),
typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
这让我在应用程序和不同类型的Collection
,甚至与不同的属性名称使用相同的UserControl
。
_“我自己弄明白了**,唯一需要改变的是ObservableCollection的类型为IEnumerable **,就像@ibebbs指出的那样**。”_ - 如果我读过一个并且答案是矛盾的临界抄袭 – MickyD
我的目的不是要拿任何信用,而是要清楚地描述在这种情况下解决我的问题的具体事情。就负面投票而言,这是我的错误,我已将其删除。但仍然@ibebbs答案完全没有解决我的问题。我只是回答了解决我的问题的具体事情,我认为这不是抄袭。 –
我唯一关心的不仅仅是DisplayMemberPath属性。我还必须使用SelectedValuePath和SelectedValue属性。我不能只为每个属性定义一个DataTemplate我猜。如果我在添加用户控件的同时必须在我的Window/Page Xaml中提供这个长项目模板,那么我不妨回过头来分离这个用户控件。 –
DataTemplates(并且,如果您决定这样做,控制模板)可以在资源字典中集中定义,因此只需定义一次即可使用,如下所示: –
ibebbs
你能提供一个例子吗? –