触发器设置器更改后未将新值设置为DependencyProperty

时间:2019-06-27 15:40:51

标签: c# wpf triggers dependency-properties

我确实试图找到解决方案,但失败了。所以我在单独的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文件中,我通过IsCheckedOnMouseEnter事件处理程序更改了OnMouseLeave。工作正常。问题是,例如,当我在GridColor事件处理程序中更改OnButtonClick时,它会更改,但是此后触发设置程序不起作用(但是另一个设置程序仍然可以正常工作)。没有例外,输出中没有消息。我错过了什么吗?

如果有人需要,这里是cs代码

  public class Control1: Control
    {
        public static readonly DependencyProperty GridColorProperty = 
            DependencyProperty.Register("GridColor", typeof(Brush), typeof(Control1), new PropertyMetadata(new SolidColorBrush(Colors.Red)));

        public static readonly DependencyProperty IsCheckedProperty = 
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(Control1), new PropertyMetadata(false));

        public Brush GridColor
        {
            get { return (Brush)GetValue(GridColorProperty); }
            set { SetValue(GridColorProperty, value); }
        }

        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            ((Grid)GetTemplateChild("PART_Grid")).MouseEnter += Grid_MouseEnter;
            ((Grid)GetTemplateChild("PART_Grid")).MouseLeave += Grid_MouseLeave;
            ((Button)GetTemplateChild("PART_Button")).Click += Button_Click;
            base.OnApplyTemplate();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            GridColor = new SolidColorBrush(Colors.DarkBlue);
        }

        private void Grid_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            IsChecked = false;
        }

        private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            IsChecked = true;
        }
    }

1 个答案:

答案 0 :(得分:0)

您似乎遇到了dependency property value precedence的问题:在我看来,您正在单击处理程序中设置本地值(链接的优先级列表中的#3),并且该值覆盖了设置的值通过控制模板触发器(优先级列表中的#4a)。

唯一要混合优先级的时间是显式地替换默认样式或基类中已完成的操作或该性质的操作。

但是您的方法仍然不是最好的主意:理想情况下,您编写WPF控件就像无权访问源代码的陌生人必须编写默认样式和默认模板一样。然后,您就像是一个陌生人一样编写默认模板。模板可能需要了解的所有内容都应作为属性完全暴露。

这并非总是可能的,但在这种情况下,我将向您展示如何做到这一点。

蓝色画笔指示一种状态:已单击该按钮。该状态不会在任何地方显式存储或公开,它只是隐含在GridColor属性的值中(您实际上应该将其命名为GridBrushGridBackground,因为它不是{{ 1}})。

因此,我们为该状态添加一个只读依赖项属性,并将有关画笔颜色的决定推到它所属的模板中。这确实很强大,因为如果您希望某些同级控件根据我们的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;
}