触发器设置器在更改后不会为 DependencyProperty 设置新值

我真的试图找到解决方案,但我失败了。所以我在单独的 xaml 文件中有 ResourceDictionary,在另一个 cs 文件中有 Control 类。这是 xaml 代码:


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                    xmlns:local="clr-namespace:WpfApp1" x:Class="Control1">

    <Style TargetType="{x:Type local:Control1}">

        <Setter Property="GridColor" Value="Red"/>

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="{x:Type local:Control1}">

                    <Grid>

                        <Grid.ColumnDefinitions>

                            <ColumnDefinition/>

                            <ColumnDefinition/>

                        </Grid.ColumnDefinitions>

                        <Grid x:Name="PART_Grid" Background="{TemplateBinding GridColor}" 

                              Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>

                        <Button Grid.Column="1" x:Name ="PART_Button" Width="50" Height="50"/>

                    </Grid>

                    <ControlTemplate.Triggers>

                        <Trigger Property="IsChecked" Value="True">

                            <Setter Property="GridColor" Value="Black"/>

                        </Trigger>

                    </ControlTemplate.Triggers>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

</ResourceDictionary>

在 cs 文件中,我更改了IsChecked事件处理OnMouseEnter程序OnMouseLeave。它工作正常。问题是,例如,当我更改事件处理GridColor程序OnButtonClick时,它会更改,但之后触发器设置器不起作用(但另一个设置器仍然可以正常工作)。没有例外,输出中没有消息。我错过了什么?

慕莱坞森
浏览 106回答 1
1回答

波斯汪

您似乎遇到了依赖属性值优先级的问题:在我看来,您正在点击处理程序中设置本地值(链接优先级列表中的#3),并且覆盖了控件模板设置的值触发器(优先列表中的#4a)。您唯一想要混合优先级的情况是当您明确想要替换以默认样式或基类或类似性质完成的内容时。但是您的方法无论如何都不是最好的主意:理想情况下,您编写 WPF 控件就像一个无法访问源代码的陌生人将不得不编写默认样式和默认模板一样。然后你像陌生人一样编写你的默认模板。模板可能需要知道的任何内容都应该清楚地公开为属性。这并不总是可行的,但我将演示如何在这种情况下做到这一点。蓝色画笔表示一种状态:按钮已被点击。该状态未显式存储或暴露在任何地方,它只是隐含在属性的值中GridColor(您实际上应该将其命名为GridBrushor GridBackground,因为它不是Color)。因此,让我们为该状态添加一个只读依赖属性,并将有关画笔颜色的决定推到它所属的模板中。这真的很强大,因为如果你想让一些兄弟控件根据我们的状态改变它的HasBeenClicked状态,你可以只在父视图中添加一个绑定。HasBeenClicked如果您希望控件的使用者能够以编程方式或通过绑定更改该状态,您还可以创建一个常规的读/写依赖属性。//  This is not a good name, but I don't know what your semantics are. public bool HasBeenClicked{    get { return (bool)GetValue(HasBeenClickedProperty); }    protected set { SetValue(HasBeenClickedPropertyKey, value); }}internal static readonly DependencyPropertyKey HasBeenClickedPropertyKey =    DependencyProperty.RegisterReadOnly(nameof(HasBeenClicked), typeof(bool), typeof(Control1),        new PropertyMetadata(false));public static readonly DependencyProperty HasBeenClickedProperty = HasBeenClickedPropertyKey.DependencyProperty;private void Button_Click(object sender, RoutedEventArgs e){    HasBeenClicked = true;}在控制模板中:<ControlTemplate.Triggers>    <!--     The last applicable trigger wins: If both are true, GridColor will be Black     -->    <Trigger Property="HasBeenClicked" Value="True">        <Setter Property="GridColor" Value="DarkBlue"/>    </Trigger>    <Trigger Property="IsChecked" Value="True">        <Setter Property="GridColor" Value="Black"/>    </Trigger></ControlTemplate.Triggers>
打开App,查看更多内容
随时随地看视频慕课网APP