如何将与DataType一起使用的DataTemplate与GridView一起使用?

时间:2012-09-19 19:12:33

标签: c# .net wpf xaml datatemplate

在你回答之前:这个问题是关于WPF的ListView控件(GridView)。关于WPF的DataGrid控件,ASP.NET的DataGridListView控件或WinForm的DataGridViewListView控件, 。它们听起来非常相似并经常混淆,但错误控制类型的答案对我来说无益,更重要的是浪费你写答案的时间,我认为不应该浪费。


我有一个ListView控件,GridView有几列绑定到我的视图模型的属性。通过指定GridViewColumn(内联或通过资源),我可以轻松自定义CellTemplate单元格的视觉外观。

现在我的视图模型上有一个特定的属性;它的类型是一个抽象基类,它的值可以是几种派生类型之一。每个派生类型在单元格中应该具有不同的DataTemplate。幸运的是,GridViewColumn有一个CellTemplateSelector,它完全符合我的要求,但需要编写一些管道代码。但是查看DataTemplateSelector的页面,它说:

  

请注意,如果您有不同类型的对象,则可以在DataTemplate上设置DataType属性。如果这样做,则无需创建DataTemplateSelector。 [...]有关详细信息,请参阅Data Templating Overview

乌拉!无需编写管道代码。我的类型 不同,所以这看起来非常合适。但是,即使我定义DataTemplate DataTypeGridViewColumn匹配其中一个数据绑定列的特定派生类型(使用DisplayMemberBinding的{​​{1}}绑定),没有效果。

我只想根据DataTemplate中某个列的运行时类型显示不同的GridViewDataType - 定位DataTemplatesGridView完全不兼容吗?有没有办法使用它们,还是我必须指定CellTemplateSelector?也许有一种方法可以在DataTemplate的{​​{1}}内指定多个GridViewColumn,以便CellTemplate属性有效?

2 个答案:

答案 0 :(得分:7)

WPF允许您在逻辑树中插入ViewModels等对象,而DataTemplate可用于告诉WPF在绘制可视树时如何绘制指定的对象。

隐式DataTemplate是仅DataTemplate定义的DataType(无x:Key),并且只要WPF尝试呈现对象,它就会自动使用VisualTree中指定的类型。

所以,你可以使用

<Window.Resources>

    <DataTemplate DataType="{x:Type local:ViewModelA}">
        <local:ViewA />
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:ViewModelB}">
        <local:ViewB />
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:ViewModelC}">
        <local:ViewC />
    </DataTemplate>

</Window.Resources>

告诉WPF使用ViewA绘制ViewModelA,使用ViewB绘制ViewModelB,使用ViewC绘制ViewModelC。

如果您只希望将此应用于GridView而不是整个Window,则可以指定<GridView.Resources>(或<ListView.Resources>,我不记得是哪一个)

应该注意的是,如果您使用DisplayMemberBinding绑定列,它将呈现为TextBox,其Text值绑定到您的属性,这意味着它将呈现YourViewModel.ToString()而不是尝试使用DataTemplate在VisualTree中绘制ViewModel。

为避免这种情况,只需将CellTemplate设置为ContentPresenterContent属性绑定到ViewModel,它就会使用隐式呈现ViewModel DataTemplates

<GridViewColumn Header="Some Header">
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding YourViewModelProperty}" />
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>

答案 1 :(得分:1)

DisplayMember*属性的实现是垃圾,我不知道为什么他们认为绑定TextBlock而不是ContentPresenter是个好主意。

我建议使用attached property或具有相应属性的子类来覆盖它。您只需要创建一个DataTemplate,其中ContentPresenter的{​​{1}}绑定到目标属性,这将允许隐式Content。然后,应将此延期DataTemplating指定为列的DataTemplate