Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在UserControl内部使组合框项Source通用,以使其可用于多种类型的集合_C#_Wpf_Generics_User Controls_Dependency Properties - Fatal编程技术网

C# 在UserControl内部使组合框项Source通用,以使其可用于多种类型的集合

C# 在UserControl内部使组合框项Source通用,以使其可用于多种类型的集合,c#,wpf,generics,user-controls,dependency-properties,C#,Wpf,Generics,User Controls,Dependency Properties,我正在开发一个WPF应用程序,最近遇到了一个要求,即制作可重用的用户控件 我有两个用户控件InputUC和ComboBoxUC。它们分别具有标签和文本框以及标签和组合框。通过定义所需的依赖属性,我成功地实现了InputUC 我面临的问题在ComboBoxUC中。在我的应用程序中有一个场景,我必须显示城市的集合,客户,销售人员以及不同地方的一些其他实体。显然,每个实体都将为DisplayMemberPath、SelectedValuePath、SelectedValuePath属性提供不同的属性名

我正在开发一个
WPF
应用程序,最近遇到了一个要求,即制作可重用的
用户控件

我有两个
用户控件
InputUC
ComboBoxUC
。它们分别具有
标签
文本框
以及
标签
组合框
。通过定义所需的依赖属性,我成功地实现了
InputUC

我面临的问题在
ComboBoxUC
中。在我的应用程序中有一个场景,我必须显示
城市的
集合
客户
销售人员
以及不同地方的一些其他实体。显然,每个实体都将为
DisplayMemberPath
SelectedValuePath
SelectedValuePath
属性提供不同的属性名称,并将
集合的不同类型作为
项目资源
组合框的属性

我也在网上搜索过,但没有找到任何相同的解决方案

我正在尝试的代码是

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>
我正在使用此
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>
我也尝试了
对象
类型的
集合
,但当然
对象
类型在我的实体中没有任何属性


由于我陷入困境,无法从现在开始继续开发,我将非常感谢您的帮助。

您不应该试图通过将集合设置为泛型来将它们设置为强类型,而应该将它们设置为不太强类型;记住,组合框本身的ItemsSource只是“object”类型

我建议您让ComboBoxUC公开IEnumerable类型的DependencyProperty,并将其绑定到ComboBox ItemsSource。然后还公开DataTemplate类型的DependencyProperty,并将其绑定到ComboBox的ItemTemplate属性。当使用用户控件时,您可以提供一个简单的DataTemplate来显示所需的属性,而不是使用DisplayMember path。例如,当您希望在ComboboxUC中显示城市的时,可以执行以下操作:

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

然后,我会将组合框的SelectedItem作为用户控件的从属属性公开,如果您必须绑定到SelectedValuePath而不是SelectedItem,请使用ValueConverter


老实说,感觉这些用户控件有点过时了。如果您获得的只是一个标签和一些样式,那么可以通过在资源字典中重新配置控件并将模板应用于您希望以这种方式使用的每个组合框来实现这一点。

而不是试图通过使集合成为泛型来使集合在用户控件中或强类型化,相反,你应该减少它们的强类型;记住,组合框本身的ItemsSource只是“object”类型

我建议您让ComboBoxUC公开IEnumerable类型的DependencyProperty,并将其绑定到ComboBox ItemsSource。然后还公开DataTemplate类型的DependencyProperty,并将其绑定到ComboBox的ItemTemplate属性。当使用用户控件时,您可以提供一个简单的DataTemplate来显示所需的属性,而不是使用DisplayMember path。例如,当您希望在ComboboxUC中显示城市的时,可以执行以下操作:

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

然后,我会将组合框的SelectedItem作为用户控件的从属属性公开,如果您必须绑定到SelectedValuePath而不是SelectedItem,请使用ValueConverter


老实说,感觉这些用户控件有点过时了。如果你得到的只是一个标签和一些样式,同样可以通过在资源字典中重新部署控件并将模板应用于您希望以这种方式使用的每个组合框来实现。

唯一需要更改的是@ibebs指出的
observeCollection
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 });

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

唯一需要改变的是@ibebs指出的
observeablecollection
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 });

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

我唯一关心的不仅仅是DisplayMemberPath属性。我还必须使用SelectedValuePath和SelectedValue属性。我不能为每个属性定义一个数据模板。如果在添加用户控件时必须在我的窗口/页面Xaml中提供此长项目模板,那么我最好返回到分离此用户控件可以在资源字典中集中定义,因此它们只需要定义一次,并且可以这样使用:您可以提供一个示例吗?SelectedValuePath可以通过SelectedValue属性上的ValueConverter派生。无论如何,我仍然觉得你在这里把事情复杂化了,使用用户控件包装一个组合框仅仅是为了获得一个标签是过分的。很抱歉Umair,但你的问题中没有任何东西表明你是WPF的新手,如果你不是新手,那么像ResourceDictionary这样的术语,DataTemplate和ValueConverter应该是第二天性。我非常鼓励你们在继续当前的道路之前阅读这些条款,因为这样你们将毫无疑问地能够回答自己的问题。我唯一关心的不仅仅是展示