wpf GridViewColumn CellTemplate 中每个 DataType 的 DataTemplate
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14652519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataTemplate for each DataType in a GridViewColumn CellTemplate
提问by scuba88
I have an ObservableCollection which contains view models of multiple types, and I would like to make a DataTemplate for each type within each of my GridViewColumn's CellTemplates. In this simple example I could create a base ViewModel, but I would like to be able to do this just from xaml. The xaml below shows what I am trying to do, where one of the DataTemplates would be used for each CellTemplate.
我有一个 ObservableCollection,它包含多种类型的视图模型,我想为每个 GridViewColumn 的 CellTemplates 中的每种类型制作一个 DataTemplate。在这个简单的示例中,我可以创建一个基本的 ViewModel,但我希望能够仅从 xaml 执行此操作。下面的 xaml 显示了我想要做什么,其中一个 DataTemplates 将用于每个 CellTemplate。
If there were a GridViewColumn.Resources I would define the DataTemplates there then use a a DataTemplate with ContentPresenter in the CellTemplate, but I obviously can't do that. I'm thinking I may need a TemplateSelector, but I'm not sure where to start.
如果有一个 GridViewColumn.Resources,我会在那里定义 DataTemplates,然后在 CellTemplate 中使用带有 ContentPresenter 的 DataTemplate,但我显然不能这样做。我想我可能需要一个 TemplateSelector,但我不确定从哪里开始。
<ListView ItemsSource={Binding GenericObservableCollection>
<ListView.View>
<GridView>
<GridViewColumn Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="Input"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="Output"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Value">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="{Binding Property1}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="{Binding Property2}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
回答by John Bowen
There are a few different ways you could go here. You could write a DataTemplateSelector and assign that to the GridViewColumn.CellTemplateSelectorproperty:
您可以通过几种不同的方式来这里。您可以编写一个 DataTemplateSelector 并将其分配给GridViewColumn.CellTemplateSelector属性:
public class ViewModelTemplateSelector : DataTemplateSelector
{
public DataTemplate InputTemplate { get; set; }
public DataTemplate OutputTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return (item is ActionInputViewModel) ? InputTemplate : OutputTemplate;
}
}
Then you can move all the templates to Resources somewhere - here I've just stuck it in the ListView for brevity:
然后,您可以将所有模板移动到 Resources 某处 - 在这里,为了简洁起见,我只是将它放在 ListView 中:
<ListView ItemsSource="{Binding GenericObservableCollection}">
<ListView.Resources>
<DataTemplate x:Key="InLabel" DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="Input"/>
</DataTemplate>
<DataTemplate x:Key="OutLabel" DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="Output"/>
</DataTemplate>
<DataTemplate x:Key="InValue" DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="{Binding Property1}"/>
</DataTemplate>
<DataTemplate x:Key="OutValue" DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="{Binding Property2}"/>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Type">
<GridViewColumn.CellTemplateSelector>
<vm:ViewModelTemplateSelector InputTemplate="{StaticResource InLabel}" OutputTemplate="{StaticResource OutLabel}"/>
</GridViewColumn.CellTemplateSelector>
</GridViewColumn>
<GridViewColumn Header="Value">
<GridViewColumn.CellTemplateSelector>
<vm:ViewModelTemplateSelector InputTemplate="{StaticResource InValue}" OutputTemplate="{StaticResource OutValue}"/>
</GridViewColumn.CellTemplateSelector>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Alternatively, if you want to keep it all in XAML you can rely on the DataTypes to resolve the right templates for you. Normally you would just put them into the Resources collection of the closest container but unfortunately GridViewColumn isn't a UI element so doesn't have a Resources collection. You can get around this by adding in a ContentControl for each cell which can hold its own typed templates:
或者,如果您想将其全部保留在 XAML 中,您可以依靠数据类型为您解析正确的模板。通常,您只需将它们放入最近容器的 Resources 集合中,但不幸的是 GridViewColumn 不是 UI 元素,因此没有 Resources 集合。您可以通过为每个可以保存自己的类型化模板的单元格添加一个 ContentControl 来解决这个问题:
<ListView ItemsSource="{Binding GenericObservableCollection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="Input"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="Output"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Value">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:ActionInputViewModel}">
<TextBlock Text="{Binding Property1}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ActionOutputViewModel}">
<TextBlock Text="{Binding Property2}"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Either way should give you the same result.
无论哪种方式都应该给你相同的结果。

