为什么在ResourceDictionary中的ControlTemplate需要使用x:key属性?

9

考虑以下XAML文件:

<Window x:Class="ExpressionVisualizer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sle="clr-namespace:System.Linq.Expressions;assembly=System.Core"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type sle:BinaryExpression}"/>
        <ControlTemplate TargetType="{x:Type ContentControl}"/>
    </Window.Resources>
</Window>

这导致编译时出现以下错误:

添加到IDictionary的所有对象都必须具有Key属性或某些其他类型的关联键。 行10,位置10。

如果我给ControlTemplate添加一个x:key属性,它就能编译了。 但是,我不应该这样做。 ControlTemplate装饰有DictionaryKeyProperty属性,该属性将TargetType指定为关键属性。 因此,只要我为ControlTemplate指定一个TargetType,我就不需要指定一个显式的键(类似于我定义的DataTemplate不需要指定键)。
我还有第二个与之相关的问题。 如果我在XAML中以这种方式定义ControlTemplate(无论是否指定了key),它是否会自动应用于所有未指定另一个模板的ContentControl类型的控件,或者我必须将ControlTemplate嵌入到Style中才能实现?
4个回答

5

来自MSDN ControlTemplate:

如果在资源部分中有一个独立的 ControlTemplate,其 TargetType 属性设置为某个类型,则该 ControlTemplate 不会自动应用于该类型。相反,您需要指定 x:Key 并显式应用模板。

还要注意,如果模板定义包含 ContentPresenter,则 ControlTemplate 上必须使用 TargetType 属性。

因此,ControlTemplate 不会自动应用,您必须始终指定 x:Key。因此,DictionaryKeyProperty 不适用。

我进行了一些研究:

尽管 DictionaryKeyPropertyAttribute MSDN 页面指出:

WPF Usage Notes

The following list references examples of WPF APIs where this attribute is applied:

ControlTemplate.TargetType

DataTemplate.DataTemplateKey

Style.TargetType
但是在资源概述页面上,他们只提到了具有隐式键的Styles, DataTemplates和Implicit Keys。这也意味着您需要始终为ControlTemplate指定x:Key,尽管存在DictionaryKeyProperty
顺便说一下,DictionaryKeyPropertyAttirubte似乎有问题,请参阅连接问题

这回答了我问题的第二部分。我知道如果我想在文档的其他地方引用模板,我需要指定一个x:Key,但是省略它不应该导致编译错误。 - luksan
我已经更新了我的答案。似乎DictionaryKeyProperty没有做它应该做的事情... - nemesv
DictionaryKeyProperty的问题似乎不会影响所有类型,因为该属性在DataTemplate上按规定工作。Connect问题来自于2009年。我想我只能把这个问题当作WPF中另一个无法正常工作并且从未经过彻底测试的事情了。每次我尝试在WPF中开发东西时,都会遇到这些类型的问题。这在Windows Forms中永远不会发生,一切都正常工作。我真的认为(或许是一厢情愿)他们在4.0版本中会使WPF更加可预测/可用。 - luksan
@nemesv,微软连接已经“退役” - 链接现在已经失效。 - Graviton

1

我不知道你第一个问题的答案,但是关于第二个问题:

我有一个与此相关的第二个问题。如果我在XAML中以这种方式定义ControlTemplate(无论是否指定键),它会自动应用于所有未指定其他模板的ContentControl类型的控件吗?还是我必须将ControlTemplate嵌入到Style中才能实现这一点?

不,它不会自动应用。如果样式的键与控件的DefaultStyleKey匹配,则样式会自动应用;如果ContentControl的Content类型与模板的DataType匹配,则数据模板会自动选择。但对于控件模板来说并非如此;无论如何,控件模板通常作为控件样式的一部分定义,它们很少直接应用于控件。


1
如果您希望控件模板应用于所有指定类型,可以定义一个样式并设置Template属性,然后将该样式的TargetType设置为您指定的控件:
<Window x:Class="ExpressionVisualizer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sle="clr-namespace:System.Linq.Expressions;assembly=System.Core"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="DT" DataType="{x:Type sle:BinaryExpression}"/>
    <ControlTemplate x:Key="CT" TargetType="{x:Type ContentControl}"/>
    <Style TargetType="ContentControl">
        <Setter Property="Template" Value="{StaticResource  CT}"></Setter>
    </Style>
</Window.Resources>

我已经测试了这个按钮的目标类型,但我认为它应该以这种方式工作。


0
<Window x:Class="ExpressionVisualizer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sle="clr-namespace:System.Linq.Expressions;assembly=System.Core"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="DT" DataType="{x:Type sle:BinaryExpression}"/>
    <ControlTemplate x:Key="CT" TargetType="{x:Type ContentControl}"/>
</Window.Resources>

Key被用于对控件应用模板,如按钮、文本框、文本块等。如果不使用它,则模板将无法工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接