在UserControl中创建组合框ItemsSource通用,使其可以重复使用多种类型的集合

时间:2016-09-03 09:00:13

标签: c# wpf generics user-controls dependency-properties

我正在处理WPF应用程序,最近遇到了重复使用User Controls的要求。

我有两个User Controls InputUCComboBoxUC。两者分别为Label TextBoxLabel ComboBox。我已经通过定义所需的依赖项属性成功实现了InputUC

我面临的问题是ComboBoxUC。我的应用程序中有一个场景,我必须在CollectionCitiesCustomers和其他一些实体显示Salesmen。显然,每个实体都会为DisplayMemberPathSelectedValuePathSelectedValue属性提供不同的属性名称,并为Collection的{​​{1}}属性提供不同类型的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> 。 在每种情况下可能有所不同的事情是:

  • CustomerViewModel.customer_city_id
  • 城市
  • CITY_NAME
  • city_id

我已在xaml中正确设置DataContext,而ComboBoxUC.xaml的当前代码可正常用于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 }); Collection类型,但当然object类型没有我实体中的任何属性。

帮助将受到赞赏,因为我陷入困境,无法从这一点开始进行开发。

2 个答案:

答案 0 :(得分:2)

而不是试图通过使用户控件中的集合通过使它们成为通用的强类型,而不是试图使它们的类型强度更低;记住,Combobox本身的ItemsSource只是'object'类型。

我建议您让ComboBoxUC公开IEnumerable类型的DependencyProperty并将其绑定到ComboBox ItemsSource。然后还公开DataTemplate类型的DependencyProperty并将其绑定到ComboBox的ItemTemplate属性。使用用户控件时,您可以提供一个简单的DataTemplate来显示所需的属性,而不是使用DisplayMember路径。例如,当您想要在ComboboxUC中显示City时,您可以这样做:

<local:ComboBoxUC ItemsSource="{Binding Cities}">
  <local.ComboBoxUC.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding city_name}"/>
    </DataTemplate>
  </local:ComboBoxUC.ItemTemplate>
</local:ComboBoxUC/>

然后我将ComboBox的SelectedItem公开为用户控件的DependencyProperty,如果绝对必须绑定到SelectedValuePath而不是SelectedItem,请使用ValueConverter。

说实话,感觉这些用户控件有点OTT。如果您获得的只是一个标签和一些样式,那么可以通过重新模板化资源字典中的控件并将模板应用于您想要以这种方式使用的每个组合框来实现相同的目标。

答案 1 :(得分:-1)

唯一需要改变的是@ibebbs指出的ObservableCollectionIEnumerable的类型。

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 });

这允许我在应用程序上使用相同的UserControl,并使用不同类型的Collection,甚至使用不同的属性名称。