在 ControlTemplate 的 DataTrigger 中使用时,TemplatedParent 为空
TemplatedParent is null when used inside a ControlTemplate's DataTrigger
考虑这个(编辑过的)Style
,专为 Button
设计,其 Content
是 String
:
<Style x:Key="Test" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text" Text="{TemplateBinding Content}" />
<TextBlock x:Name="demo" Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="test" Property="Foreground" Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
此示例的目的是在按钮文本等于单词 "Test"1 时将其变为红色。但它不起作用,因为触发器的 TemplatedParent
绑定解析为 null 而不是应用 Style
的 Button
。但是,名为 "demo" 的 TextBlock
将按预期将其 Text
设置为 "System.Windows.Controls.Button: [ButtonText]",这意味着 TemplatedParent
在该级别可以正常工作。为什么它在 DataTrigger
中不起作用?
1 我知道还有其他方法可以实现这一点,但我想了解为什么绑定无法按我预期的方式工作。
我不太确定,但我认为触发器等于引用,因为内容 returns 是一个对象。因此,您在触发器中定义的字符串永远不会成立。
TemplatedParent
在您的 ControlTemplate.Triggers
中不是您所期望的。在触发器内部,它实际上引用了 Button.TemplatedParent
。因此,如果您在模板中创建 button ,它只会是非空的。您不会在模板内创建按钮,因此在您的情况下它为空。现在考虑这个 xaml:
<Window.Resources>
<Style x:Key="Test"
TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text"
Text="dummy" />
<TextBlock x:Name="demo"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="text"
Property="Foreground"
Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Test2" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Button Style="{StaticResource Test}"></Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<!--<Button Content="Test" Style="{StaticResource Test}"/>-->
<ContentControl Style="{StaticResource Test2}" Content="Test" />
</Grid>
我在这里重新模板化 ContentControl
并在模板内部使用 按钮和您的模板 。如果您 运行 此代码,您将看到 "dummy" 红色文本,因为 Button.TemplatedParent
现在是 ContentControl
,并且 Content
等于 "Test",这证实了我上面说的。
现在回到您的问题:只需将 RelativeSource TemplatedParent
更改为 RelativeSource Self
(无需将 DataTrigger
更改为 Trigger
)- 这个将引用您的 Button。
我认为这可能是 .NET Core WPF 中的类似问题。
我的 DataTrigger
没有用 {Binding MyProp, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Convert}}
触发,而是当我将 RelativeSource 更改为 Self
时绑定开始工作。我不确定这是黑客攻击还是解决方案,但它确实有效。
也许值得一提的是,我的模板基于 MyView
(见下文)并且我绑定到 MyView
上的 DependencyProperty
。
所以我的最终代码如下所示:
<ControlTemplate x:Key="Template" TargetType="{x:Type ns:MyView}">
<!-- Some template -->
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding MyProp, RelativeSource={RelativeSource Self}, Converter={StaticResource Convert}}" Value="True">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
考虑这个(编辑过的)Style
,专为 Button
设计,其 Content
是 String
:
<Style x:Key="Test" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text" Text="{TemplateBinding Content}" />
<TextBlock x:Name="demo" Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="test" Property="Foreground" Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
此示例的目的是在按钮文本等于单词 "Test"1 时将其变为红色。但它不起作用,因为触发器的 TemplatedParent
绑定解析为 null 而不是应用 Style
的 Button
。但是,名为 "demo" 的 TextBlock
将按预期将其 Text
设置为 "System.Windows.Controls.Button: [ButtonText]",这意味着 TemplatedParent
在该级别可以正常工作。为什么它在 DataTrigger
中不起作用?
1 我知道还有其他方法可以实现这一点,但我想了解为什么绑定无法按我预期的方式工作。
我不太确定,但我认为触发器等于引用,因为内容 returns 是一个对象。因此,您在触发器中定义的字符串永远不会成立。
TemplatedParent
在您的 ControlTemplate.Triggers
中不是您所期望的。在触发器内部,它实际上引用了 Button.TemplatedParent
。因此,如果您在模板中创建 button ,它只会是非空的。您不会在模板内创建按钮,因此在您的情况下它为空。现在考虑这个 xaml:
<Window.Resources>
<Style x:Key="Test"
TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text"
Text="dummy" />
<TextBlock x:Name="demo"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="text"
Property="Foreground"
Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Test2" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Button Style="{StaticResource Test}"></Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<!--<Button Content="Test" Style="{StaticResource Test}"/>-->
<ContentControl Style="{StaticResource Test2}" Content="Test" />
</Grid>
我在这里重新模板化 ContentControl
并在模板内部使用 按钮和您的模板 。如果您 运行 此代码,您将看到 "dummy" 红色文本,因为 Button.TemplatedParent
现在是 ContentControl
,并且 Content
等于 "Test",这证实了我上面说的。
现在回到您的问题:只需将 RelativeSource TemplatedParent
更改为 RelativeSource Self
(无需将 DataTrigger
更改为 Trigger
)- 这个将引用您的 Button。
我认为这可能是 .NET Core WPF 中的类似问题。
我的 DataTrigger
没有用 {Binding MyProp, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Convert}}
触发,而是当我将 RelativeSource 更改为 Self
时绑定开始工作。我不确定这是黑客攻击还是解决方案,但它确实有效。
也许值得一提的是,我的模板基于 MyView
(见下文)并且我绑定到 MyView
上的 DependencyProperty
。
所以我的最终代码如下所示:
<ControlTemplate x:Key="Template" TargetType="{x:Type ns:MyView}">
<!-- Some template -->
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding MyProp, RelativeSource={RelativeSource Self}, Converter={StaticResource Convert}}" Value="True">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>