简体   繁体   English

在 ControlTemplate 的 DataTrigger 中使用时,TemplatedParent 为 null

[英]TemplatedParent is null when used inside a ControlTemplate's DataTrigger

Consider this (edited-down) Style , designed for a Button whose Content is a String :考虑这个(编辑过的) 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>

The intention in this example is to turn the button text red if it equals the word "Test" 1 .此示例中的意图是将按钮文本变为红色,如果它等于单词 "Test" 1 But it doesn't work, because the trigger's TemplatedParent binding resolves to null instead of to the Button the Style is applied to.但它不起作用,因为触发器的TemplatedParent绑定解析为 null 而不是应用StyleButton However, the TextBlock named "demo" will have its Text set to "System.Windows.Controls.Button: [ButtonText]" as expected, which means TemplatedParent works correctly at that level.但是,名为“demo”的TextBlock将按预期将其Text设置为“System.Windows.Controls.Button: [ButtonText]”,这意味着TemplatedParent在该级别正常工作。 Why doesn't it work inside the DataTrigger ?为什么它在DataTrigger


1 I know there are other ways to achieve that, but I'm trying to understand why the binding doesn't work the way I expect it to. 1我知道还有其他方法可以实现这一点,但我试图理解为什么绑定不能按我期望的方式工作。

TemplatedParent in your ControlTemplate.Triggers is not what you expect.ControlTemplate.Triggers TemplatedParent不是您所期望的。 Inside trigger it actually references Button.TemplatedParent .在触发器内部,它实际上引用了Button.TemplatedParent As such, it will only be non-null if your create that button inside template.因此,如果您在模板中创建该按钮,它只会是非空的。 You don't create button inside template, so it is null in your case.您不在模板内创建按钮,因此在您的情况下它为空。 Now consider this xaml:现在考虑这个 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>

Here I retemplate ContentControl and inside template I use button with your template .在这里,我重新模板ContentControl和内部模板我使用按钮与您的模板 If you run this code, you will see "dummy" text in red, because Button.TemplatedParent is now ContentControl , and it has it's Content equals "Test", which confirms what I said above.如果您运行此代码,您将看到红色的“虚拟”文本,因为Button.TemplatedParent现在是ContentControl ,并且它的Content等于“Test”,这证实了我上面所说的。

Now back to your problem: just change RelativeSource TemplatedParent to RelativeSource Self (no need to change DataTrigger to Trigger ) - this one would reference your Button.现在回到您的问题:只需将RelativeSource TemplatedParent更改为RelativeSource Self (无需将DataTrigger更改为Trigger )-这将引用您的按钮。

I think it might be a similar issue in .NET Core WPF.我认为这可能是 .NET Core WPF 中的类似问题。 My DataTrigger was not firing with {Binding MyProp, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Convert}} , but instead when I changed the RelativeSource to Self the binding started to work.我的DataTrigger没有用{Binding MyProp, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Convert}}触发,而是当我将 RelativeSource 更改为Self ,绑定开始工作。 I'm not sure whether it's a hack or a solution, but it worked.我不确定这是黑客攻击还是解决方案,但它有效。

Maybe it's worth mentioning that my template was based on MyView (see below) and I was binding to a DependencyProperty on MyView .也许值得一提的是,我的模板基于MyView (见下文),并且我绑定到了MyView上的DependencyProperty

So my final code looked like this:所以我的最终代码如下所示:

<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>

I'm not quite sure, but I think the trigger equals by referenc, because Content returns an Object.我不太确定,但我认为触发器等于引用,因为内容返回一个对象。 So it will never be true with your string defined within the trigger.因此,在触发器中定义的字符串永远不会是真的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM