元素属性语法和属性属性语法之间是否存在语义差异?

时间:2010-07-18 21:42:27

标签: c# .net wpf xaml exception

我认为元素属性语法和属性属性语法没有很大的语义差异。但是,我发现必须有一些区别。

E.g。以下示例仅演示了一个简单的触发器:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button><Button.Template>
  <ControlTemplate TargetType="{x:Type Button}">
    <TextBlock x:Name="hello" Text="Hello" />
    <ControlTemplate.Triggers>
      <Trigger Property="IsMouseOver" Value="True">
        <Setter Property="Foreground" Value="Red" TargetName="hello"/>
     </Trigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
</Button.Template></Button>
</Page>

但是,如果我对触发器的属性Property使用了元素属性语法,则会抛出一个异常,说明了setter! (不是触发器)需要属性和值。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button><Button.Template>
  <ControlTemplate TargetType="{x:Type Button}">
    <TextBlock x:Name="hello" Text="Hello" />
    <ControlTemplate.Triggers>
      <Trigger Value="True">
        <Trigger.Property>IsMouseOver</Trigger.Property>
        <Setter Property="Foreground" Value="Red" TargetName="hello"/>
     </Trigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
</Button.Template></Button>
</Page>

那么,元素属性语法和属性属性语法之间的隐藏区别是什么?

1 个答案:

答案 0 :(得分:2)

应该没有区别。我想你刚刚在XAML解析器中发现了一个错误。

框架对Setter,Trigger和Condition有特殊处理。使用Reflector检出Trigger.ReceiveTypeConverter,它会覆盖Value和Property属性的属性设置器的处理。我认为这是因为它可以使用基于Property属性的不同类型解析Value属性。例如,当它看到Property是Foreground并且Foreground是Brush类型时,它将“Red”解析为Brush而不仅仅是String。

看起来该钩子会覆盖Trigger中名为Value或Property的所有属性集,但它不能正确处理元素属性语法。要查看效果,请尝试创建如下标记扩展名:

public class Test
    : MarkupExtension
{
    public DependencyProperty Property { get; set; }
    public DependencyProperty Property2 { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Property ?? Property2;
    }
}

以下XAML将获得与第二个示例相同的错误,您可以通过设置断点来验证从未设置Property:

<Trigger.Property>
    <local:Test>
        <local:Test.Property>IsMouseOver</local:Test.Property>
    </local:Test>
</Trigger.Property>

但是,这样可行,因为该属性未命名为“Property”:

<Trigger.Property>
    <local:Test>
        <local:Test.Property2>IsMouseOver</local:Test.Property2>
    </local:Test>
</Trigger.Property>

这样可行,因为它使用了属性语法:

<Trigger.Property>
    <local:Test Property="IsMouseOver"/>
</Trigger.Property>

如果您确实需要使用element属性语法,那么将为您提供一种解决方法:创建一个MarkupExtension,其属性类型为DependencyProperty,而不是“Property”,并在ProvideValue中返回。