Установщик триггера не устанавливает новое значение в DependencyProperty после его изменения - PullRequest
0 голосов
/ 27 июня 2019

Я действительно пытался найти решение, но мне не удалось.Итак, у меня есть ResourceDictionary в отдельном файле xaml и класс Control в другом файле cs.Вот код 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 обработчике событий, он меняется, но после этого установщик триггера не работает (но другие установщики все еще работают нормально).Нет исключений, нет сообщений на выходе.Я что-то пропустил?

Вот код 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 голосов
/ 27 июня 2019

Вы, похоже, столкнулись с проблемой приоритета значения свойства зависимости : мне кажется, что вы устанавливаете локальное значение (# 3 в связанном списке приоритетов) в обработчике кликов, иэто переопределяет значение, установленное триггером шаблона управления (# 4a в списке приоритетов).

Единственный раз, когда вы хотите смешать приоритеты, это когда вы явно хотите заменить что-то, выполненное в стиле по умолчанию, базовый класс или что-то в этом роде.

Но ваш подход в любом случае не лучшая идея: в идеале вы пишете элементы управления WPF, как если бы незнакомец, не имеющий доступа к источнику, должен был написать стиль по умолчанию и шаблон по умолчанию.А потом вы пишете шаблон по умолчанию, как если бы вы были незнакомцем.Все, что шаблону может понадобиться знать, должно быть открыто представлено как свойство.

Это не всегда возможно, но я покажу, как вы можете это сделать в этом случае.

Синяя кисть указывает состояние: нажата кнопка.Это состояние нигде не хранится и не отображается явно, оно просто подразумевается в значении свойства GridColor (которое вы действительно должны были бы назвать GridBrush или 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>
...