wpf - GridViewColumn 中每个数据类型的 DataTemplate CellTemplate

标签 wpf datatemplate gridviewcolumn celltemplate

我有一个 ObservableCollection,其中包含多种类型的 View 模型,我想为每个 GridViewColumn 的 CellTemplates 中的每种类型创建一个 DataTemplate。在这个简单的示例中,我可以创建一个基本 ViewModel,但我希望能够仅从 xaml 中执行此操作。下面的 xaml 显示了我正在尝试执行的操作,其中每个 CellTemplate 将使用一个 DataTemplate。

如果有 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>

最佳答案

您可以通过几种不同的方式到达这里。您可以编写一个 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;
    }
}

然后您可以将所有模板移动到资源中的某个位置 - 为了简洁起见,我只是将其粘贴在 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>

或者,如果您想将所有内容保留在 XAML 中,您可以依靠数据类型来为您解析正确的模板。通常,您只需将它们放入最近容器的资源集合中,但不幸的是 GridViewColumn 不是 UI 元素,因此没有资源集合。您可以通过为每个可以保存自己的类型模板的单元格添加 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>

无论哪种方式都会给你相同的结果。

关于wpf - GridViewColumn 中每个数据类型的 DataTemplate CellTemplate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14652519/

相关文章:

c# - 通过反射从动态中检索属性信息

c# - EdsCreateImageRef() 方法给出 EDS_ERR_FILE_FORMAT_UNRECOGNIZED

wpf - 为什么在 DataTemplate 中使用 UserControl 比直接 xaml 慢?

wpf - DataTemplate 中的 RelativeSource 适用于 TabControl 但不适用于 TabItem

.net - WPF:如何使用 XAML 隐藏 GridViewColumn?

wpf - ListView 中 Gridview 列的内容对齐

c# - 如何以编程方式将 RibbonTab 添加到 WPF 功能区(2010 年 10 月版本)?

c# - 如何在某些 ListBox 项目上使用不同的控件模板?

WPF 内存使用情况

wpf - 在wpf treeview中,如何用以前的扩展值重绘节点(使用MVVM)