可以按类型将DataTemplate应用于DataGridTemplateColumn吗?

时间:2014-03-19 17:41:10

标签: c# wpf xaml

我为自定义类创建了一个DataTemplate,它应该用于显示文件类型的内容。

以下是放置在窗口资源字典中的示例:

    <DataTemplate DataType="namespace:Handle">
        <Border>
            <TextBlock>This is a static data template</TextBlock>
        </Border>
    </DataTemplate>

DataGridTemplateColumn CellTemplate是否可以按类型而不是x:Key引用给定的模板?

如果我使用像

这样的东西,它可以通过Key工作
<DataGridTemplateColumn Header="The file name" CellTemplate="{StaticResource myTemplate }" />

没关系,但是我可以进行类型绑定吗?

DataGrid有没有自动生成的列,并不是每个列都应该由上面的模板模板化。


编辑:这是对@Anatoliy Nikolaev的回复:我认为你的回答并非我所期望的解决方案,因为我只是使用密钥。以下是概述行为的示例:

    <DataTemplate x:Key="{x:Type system:Object}" DataType="{x:Type dataTemplateOnType:Handle}">
        <Border>
            <TextBlock>This is a static data template</TextBlock>
        </Border>
    </DataTemplate>

我可以参考:

<DataGridTemplateColumn Header="The file name" CellTemplate="{StaticResource {x:Type system:Object}}" />

这仍然只是一个复杂的密钥类型。

3 个答案:

答案 0 :(得分:1)

不可能。

请参阅http://msdn.microsoft.com/en-us/library/system.windows.controls.datagridtemplatecolumn.celltemplate(v=vs.110).aspx以供参考。

您的DataTemplate必须是实例化对象,才能将其分配给CellTemplate属性。这就是为什么你必须借助x:Key来引用你的DataTemplate实例。

答案 1 :(得分:1)

这是一个有效的例子:

<Window.Resources>
    <DataTemplate x:Key="{x:Type this:TestData}"
                  DataType="{x:Type this:TestData}">

        <TextBox Text="{Binding Path=SomeProperty}" 
                 Background="Aquamarine" />
    </DataTemplate>
</Window.Resources>

...

<DataGridTemplateColumn Header="Test" 
                        Width="*"                                        
                        CellTemplate="{StaticResource {x:Type this:TestData}}" />

如果在CellTemplate中写DynamicResource,它将无效(正如我最初尝试过的那样)。

在这种情况下,这一行:

x:Key="{x:Type this:TestData}"

必然,没有她的例子将无法奏效。但是,如果您错过了StyleDataTemplate的密钥,则此构造:

<DataTemplate TargetType="{x:Type local:MyType}">

自动转换为:

<DataTemplate x:Key="{x:Type local:MyType}" TargetType="{x:Type local:MyType}">

这意味着Style/DataTemplate将明确用于此类型的所有控件,因为在ResourceDictionaries中不能是没有键的元素,而是这样做是为了简化结构MSDN

为什么在没有钥匙的情况下这种情况不起作用?我认为这是一个错误,或者有其他限制阻止他按原样工作,但它应该没有密钥。

答案 2 :(得分:0)

据我所知,DataGrid 不支持按模板列中的类型自动选择数据模板。但是,存在允许这种行为的解决方法。关键是在能够提供这种机制的数据模板中使用 ContentControl 作为嵌套元素。

<DataGrid ...>
   <DataGrid.Resources>
      <DataTemplate DataType="{x:Type local:MyType1}">
         <!-- ...data template definition.--> 
      </DataTemplate>
      <DataTemplate DataType="{x:Type local:MyType1}">
         <!-- ...data template definition.--> 
      </DataTemplate>
      <DataTemplate x:Key="DynamicTemplateColumnCellTemplate">
         <ContentControl Content="{Binding}"/>
      </DataTemplate>
   </DataGrid.Resources>
   <DataGrid.Columns>
      <DataGridTemplateColumn CellTemplate="{StaticResource DynamicTemplateColumnCellTemplate}"/>
   </DataGrid.Columns>
</DataGrid>

如果您只想为单个列设置数据模板的范围,请将它们移到数据模板中。

<DataGrid ...>
   <DataGrid.Columns>
      <DataGridTemplateColumn>
         <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
               <DataTemplate.Resources>
                  <DataTemplate DataType="{x:Type local:MyType1}">
                     <!-- ...data template definition.--> 
                  </DataTemplate>
                  <DataTemplate DataType="{x:Type local:MyType1}">
                     <!-- ...data template definition.--> 
                  </DataTemplate>
               </DataTemplate.Resources>
               <ContentControl Content="{Binding}" />
            </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
      </DataGridTemplateColumn>
   </DataGrid.Columns>
</DataGrid>

这种方法存在一个问题。如果 CanUserAddRowsTrue 并且您使用具有无参数构造函数的类型集合,则 DataGrid 将添加一个附加项,该项不匹配任何数据模板类型,因此显示为通过 ToString 的纯文本,这不是您想要的。

Additional row with new item placeholder object.

这个晦涩的项目来自 DataGrid 中的一个内部属性。它是这样定义的 (reference source):

internal static object NewItemPlaceholder
{
   get { return _newItemPlaceholder; }
}

private static object _newItemPlaceholder = new NamedObject("DataGrid.NewItemPlaceholder"); // Used as an alternate data item to CollectionView.NewItemPlaceholder

为了正确显示该项目,您必须检测该项目,例如使用样式触发器,但它定义为 internal,因此您不能直接引用它。 marukp 扩展是通过反射访问它的一种方式。尽管这种方法将来可能会失效并且有些脏,但目前它很容易解决。

public class DataGridNewItemPlaceholderExtension : MarkupExtension
{
   public override object ProvideValue(IServiceProvider serviceProvider)
   {
      return typeof(DataGrid).GetProperty("NewItemPlaceholder", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
   }
}

使用这个标记扩展,我们可以在数据模板中添加一个DataTrigger,将嵌套的Content的{​​{1}}设置为空字符串,这样看起来就像默认的新项行。

ContentControl

您甚至可以为新项目占位符定义单独的数据模板。

<DataGrid ... CanUserAddRows="True">
   <DataGrid.Columns>
      <DataGridTemplateColumn>
         <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
               <DataTemplate.Resources>
                  <DataTemplate DataType="{x:Type local:MyType1}">
                     <!-- ...data template definition.--> 
                  </DataTemplate>
                  <DataTemplate DataType="{x:Type local:MyType1}">
                     <!-- ...data template definition.--> 
                  </DataTemplate>
               </DataTemplate.Resources>
               <ContentControl x:Name="ContentControl" Content="{Binding}" />
               <DataTemplate.Triggers>
                  <DataTrigger Binding="{Binding}" Value="{local:DataGridNewItemPlaceholder}">
                     <Setter TargetName="ContentControl" Property="Content" Value="{x:Static system:String.Empty}" />
                  </DataTrigger>
               </DataTemplate.Triggers>
            </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
      </DataGridTemplateColumn>
   </DataGrid.Columns>
</DataGrid>