这可能是一个显而易见的问题,但我认为实现它可能有多种方法,因此这不仅对我有用,希望对其他人也有用。
本质上,我正在寻找实现可接受不同类型对象并使用相应的项/数据模板呈现它们的列表视图的最佳方法。
例如...我们有一个标准产品列表视图,当查看不同类别时,业务已决定为每个不同类别显示不同的项目模板样式。
在这里提出这个问题的主要原因是避免使用丑陋的hacky解决方案,而是发现一个好的清洁方法。
希望我提供了足够的信息,如果需要更多信息,请告诉我。
在Resources
中只需使用相应的DataType
指定DataTemplates
即可,例如:
<ListView ItemsSource="{Binding Data}">
<ListView.Resources>
<!-- Do NOT set the x:Key -->
<DataTemplate DataType="{x:Type local:Employee}">
<TextBlock Text="{Binding Name}" Foreground="Blue"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Machine}">
<TextBlock Text="{Binding Model}" Foreground="Red"/>
</DataTemplate>
</ListView.Resources>
</ListView>
(请注意,DataTemplate.DataType
也可用于隐式 XML 数据模板化(请参阅文档),因此该属性类型不是 System.Type
,所以与 Style.TargetType
不同,您必须使用 x:Type
引用 CLR 类型。如果您只输入字符串,它将不会转换为类型。)
您可能还想了解CompositeCollections
,以获得干净的合并列表,其中包含各种类型。
我使用的示例数据:
ObservableCollection<Employee> data = new ObservableCollection<Employee>(new Employee[]
{
new Employee("Hans", "Programmer") ,
new Employee("Elister", "Programmer") ,
new Employee("Steve", "GUI Designer") ,
new Employee("Stephen", "GUI Designer") ,
new Employee("Joe", "Coffee Getter") ,
new Employee("Julien", "Programmer") ,
new Employee("John", "Coffee Getter") ,
});
ObservableCollection<Machine> data2 = new ObservableCollection<Machine>(new Machine[]
{
new Machine("XI2", String.Empty),
new Machine("MK2-xx", String.Empty),
new Machine("A2-B16", String.Empty),
});
CompositeCollection cc1 = new CompositeCollection();
cc1.Add(new CollectionContainer() { Collection = data });
cc1.Add(new CollectionContainer() { Collection = data2 });
Data = cc1;
一个选择是在您的代码中创建DataTemplateSelector:
public class QueueDisplayDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
var listBoxItem = item as JobQueueListBoxItem;
var resourceName = String.Empty;
switch (listBoxItem.JobQueueListBoxItemType)
{
case JobQueueListBoxItemType.QueuedJob :
resourceName = "DataTemplateQueuedJob";
break;
case JobQueueListBoxItemType.TransferWorker :
resourceName = "DataTemplateTransferWorker";
break;
default:
throw new InvalidOperationException(string.Format("There is no corresponding list box template for {0}", listBoxItem.JobQueueListBoxItemType));
}
var element = container as FrameworkElement;
return element.FindResource(resourceName) as DataTemplate;
}
}
这将被声明为 XAML 资源,然后可以在 XAML 中使用。 <ResourceDictionary>
<local:QueueDisplayDataTemplateSelector x:Key="QueueDisplayDataTemplateSelector" />
然后将这个赋值给您的列表框:
<ListBox ItemsSource="{Binding ListBoxContents}"
ItemTemplateSelector="{StaticResource QueueDisplayDataTemplateSelector}"
>
x:type
更加简洁,但两者在大量备选项的情况下都有些受影响。 - ocodocase
而不是使用多态来管理模板选择。 - ocodo