Поделиться через


Очередность значений свойств зависимостей

Работа системы свойств Windows Presentation Foundation (WPF) влияет на значение свойства зависимостей. В этой статье объясняется, как приоритет различных входных данных на основе свойств в системе свойств WPF определяет эффективное значение свойства зависимости.

Предпосылки

В статье предполагается, что у вас есть базовые знания о свойствах зависимости и что вы прочитали Обзор свойств зависимостей. Чтобы следовать примерам в этой статье, это поможет вам, если вы знакомы с языком разметки расширяемых приложений (XAML) и узнаете, как писать приложения WPF.

Система свойств WPF

Система свойств WPF использует различные факторы для определения значения свойств зависимостей, таких как проверка свойств в режиме реального времени, поздняя привязка и уведомления об изменении свойств для связанных свойств. Хотя порядок и логика, используемая для определения значений свойств зависимостей, сложна, обучение может помочь избежать ненужных параметров свойств, а также выяснить, почему попытка задать свойство зависимостей не привело к ожидаемому значению.

Свойства зависимостей, заданные в нескольких местах

В следующем примере XAML показано, как три разных операции "set" в свойстве кнопки Background могут влиять на его значение.

<StackPanel>
    <StackPanel.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" 
                    BorderBrush="{TemplateBinding BorderBrush}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>
        </ControlTemplate>
    </StackPanel.Resources>

    <Button Template="{StaticResource ButtonTemplate}" Background="Red">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="Blue"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        Which color do you expect?
    </Button>
</StackPanel>

В примере свойство Background локально установлено на Red. Однако неявный стиль, объявленный в области кнопки, пытается задать значение Background для свойства Blue. Когда курсор мыши находится над кнопкой, триггер в неявном стиле пытается установить для свойства Background значение Yellow. За исключением принудительного преобразования и анимации, локально заданное значение свойства имеет наивысший приоритет, поэтому кнопка будет красной, даже при наведении курсора. Но при удалении локально заданного значения с кнопки она получит своё Background значение из стиля. В рамках стиля триггеры имеют приоритет, поэтому кнопка будет жёлтой при наведении курсора и синей в остальных случаях. Пример заменяет значение шаблона кнопки по умолчанию ControlTemplate, потому что в шаблоне по умолчанию задано жестко закодированное значение наведения курсора Background.

Список приоритета свойств зависимостей

Следующий список является окончательным порядком приоритета, который система свойств использует при назначении значений среды выполнения свойствам зависимостей. Сначала указана наивысшая первоочередность.

  1. Приведение системы свойств. Для получения дополнительной информации о принуждении см. в разделе Принуждение и анимации.

  2. Активные анимации или анимации с поведением удержания. Чтобы иметь практический эффект, значение анимации должно иметь приоритет над базовым (неаниматизованным) значением, даже если базовое значение было задано локально. Дополнительные сведения см. в разделе «Приведение и анимация».

  3. Локальные значения. Можно задать локальное значение через свойство "оболочка", которое равнозначно настройке атрибута или элемента свойства в XAML, или вызовом SetValue API с помощью свойства определенного экземпляра. Локальное значение, заданное с помощью привязки или ресурса, будет иметь тот же приоритет, что и значение, которое устанавливается напрямую.

  4. Значения свойств шаблона TemplatedParent. Элемент имеет TemplatedParent, если он создан шаблоном (ControlTemplate или DataTemplate). Дополнительные сведения см. в разделе TemplatedParent. В шаблоне, указанном в TemplatedParent, порядок предпочтения:

    1. Триггеры.

    2. Наборы свойств, обычно через атрибуты XAML.

  5. Неявные стили. Применяется только к свойству Style. Значение Style — это любой ресурс стиля со TargetType значением, соответствующим типу элемента. Ресурс стиля должен существовать в пределах страницы или приложения. Поиск неявного ресурса стиля не распространяется на ресурсы стилей в темах.

  6. Триггеры стиля. Триггер стиля — это триггер в явном или неявном стиле. Стиль должен существовать в пределах страницы или приложения. Триггеры в стилях по умолчанию имеют более низкий приоритет.

  7. Триггеры шаблона. Триггер шаблона — это триггер из непосредственно примененного шаблона или из шаблона в стиле. Стиль должен существовать в пределах страницы или приложения.

  8. Значения установщика стилей. Значение установщика стиля — это значение, применяемое Setter в пределах стиля. Стиль должен существовать в пределах страницы или приложения.

  9. Стили по умолчанию, также известные как стили тем. Для получения дополнительной информации см. стили по умолчанию (Тема). В стиле по умолчанию порядок приоритета:

    1. Активные триггеры.

    2. Сеттеры.

  10. Наследование. Некоторые свойства зависимостей дочернего элемента наследуют их значение от родительского элемента. Поэтому может не потребоваться задать значения свойств для каждого элемента в приложении. Дополнительные сведения см. в разделе «Наследование значений свойств».

  11. Значение по умолчанию из метаданных свойства зависимостей Свойство зависимостей может иметь значение по умолчанию во время регистрации этого свойства системой свойств. Производные классы, наследующие свойство зависимостей, могут переопределить метаданные свойства зависимостей (включая значение по умолчанию) на основе каждого типа. Дополнительные сведения см. в разделе метаданных свойства зависимостей. Для унаследованного свойства значение по умолчанию родительского элемента имеет приоритет над значением по умолчанию дочернего элемента. Таким образом, если наследуемое свойство не задано, значение по умолчанию корневого или родительского используется вместо значения по умолчанию дочернего элемента.

TemplatedParent

TemplatedParent Приоритет не применяется к свойствам элементов, объявленных непосредственно в стандартной разметке приложения. Концепция TemplatedParent существует только для дочерних элементов в визуальном дереве, которое возникает через приложение шаблона. Когда система свойств выполняет поиск шаблона, указанного в TemplatedParent, для значений свойств элемента, то она ищет шаблон, который создал этот элемент. Значения свойств из TemplatedParent шаблона обычно действуют так, как если бы они были локально заданы в элементе, но с меньшим приоритетом, чем фактические локальные значения, так как шаблоны потенциально совместно используются. Дополнительные сведения см. в разделе TemplatedParent.

Свойство Style

Тот же порядок приоритета применяется ко всем свойствам зависимостей, кроме Style свойства. Свойство Style уникально тем, что его нельзя стилизовать. Принудительное изменение или анимация свойства Style не рекомендуется (анимация свойства Style потребует создания пользовательского класса анимации). В результате не все элементы приоритета применяются. Существует только три способа задания Style свойства:

  • Явный стиль. Свойство Style элемента задано напрямую. Значение Style свойства действует так, как будто это локальное значение и имеет то же приоритет, что и элемент 3 в списке приоритетов. В большинстве сценариев явные стили не определяются встроенными и вместо этого на них явно ссылаются как на ресурс, например Style="{StaticResource myResourceKey}".

  • Неявный стиль. Style Свойство элемента не задано напрямую. Вместо этого стиль применяется, если он существует на определенном уровне в пределах страницы или приложения, и имеет ключ ресурса, соответствующий типу элемента, к которому применяется стиль, например <Style TargetType="x:Type Button">. Тип должен совпадать точно, например <Style TargetType="x:Type Button"> , не будет применяться к MyButton типу, даже если MyButton он является производным от Button. Значение Style свойства имеет тот же приоритет, что и элемент 5 в списке приоритетов. Неявное значение стиля можно обнаружить путем вызова метода DependencyPropertyHelper.GetValueSource, передачи свойства Style и проверки ImplicitStyleReference в результатах.

  • Стиль по умолчанию, также известный как стиль темы. Style Свойство элемента не задано напрямую. Вместо этого она исходит от динамической оценки темы средой выполнения движка презентаций WPF. Значение свойства Style перед запуском равно null. Значение Style свойства имеет тот же приоритет, что и элемент 9 в списке приоритетов.

Стили по умолчанию (тема)

Каждый элемент управления, который поставляется с WPF, имеет стиль по умолчанию, который может отличаться по теме, поэтому стиль по умолчанию иногда называется стилем темы.

Это ControlTemplate важный элемент в стиле по умолчанию для элемента управления. ControlTemplate — это установочное значение для свойства стиля Template. Если в стилях по умолчанию отсутствует шаблон, то элемент управления без собственного шаблона в составе пользовательского стиля не будет иметь визуального представления. Не только шаблон определяет внешний вид элемента управления, он также определяет соединения между свойствами в визуальном дереве шаблона и соответствующим классом элемента управления. Каждый элемент управления предоставляет набор свойств, которые могут повлиять на внешний вид элемента управления без замены шаблона. Например, рассмотрим визуальный вид Thumb элемента управления по умолчанию, который является компонентом ScrollBar .

Элемент Thumb управления имеет определенные настраиваемые свойства. Шаблон Thumb элемента управления по умолчанию создает базовую структуру или визуальное дерево с несколькими вложенными Border компонентами для создания фасетчатого вида. В шаблоне свойства, которые предназначены для настройки Thumb классом, предоставляются с помощью TemplateBinding

Стили по умолчанию указывают TargetType в их определениях. Оценка темы в среде выполнения сопоставляет TargetType стиль по умолчанию с DefaultStyleKey свойством элемента управления. В отличие от этого, для неявных стилей фактический тип элемента управления определяет поведение. Значение DefaultStyleKey наследуется производными классами, поэтому производные элементы, которые в противном случае не имеют связанного стиля, получают внешний вид визуального элемента по умолчанию. Например, если вы производите MyButton из Button, MyButton унаследует шаблон Button по умолчанию. Производные классы могут переопределить значение DefaultStyleKey по умолчанию в метаданных свойства зависимостей. Таким образом, если вы хотите другое визуальное отображение для MyButton, вы можете переопределить метаданные свойства зависимостей для DefaultStyleKey в MyButton, а затем определить соответствующий стиль по умолчанию, включая шаблон, который будет включен в ваш элемент управления MyButton. Дополнительные сведения см. в разделе "Обзор разработки элементов управления"

Динамический ресурс

Динамический ресурс

Динамические ссылки на ресурсы не являются технической частью системы свойств и имеют собственный порядок подстановки, взаимодействующий со списком приоритетов. По сути, порядок приоритета динамических ссылок на ресурсы: сперва элемент, затем корень страницы, приложение, тема и, наконец, система. Дополнительные сведения см. в ресурсах XAML и.

Хотя динамические ссылки на ресурсы и привязки имеют приоритет расположения, в котором они заданы, значение отложено. Одним из последствий этого является то, что при установке динамического ресурса или привязки к локальному значению любое изменение локального значения полностью заменяет динамический ресурс или привязку. Даже при вызове ClearValue метода для очистки локально заданного значения динамический ресурс или привязка не будет восстановлена. Фактически, если вы вызываете ClearValue для свойства, имеющего динамический ресурс или привязку (без локального значения), динамический ресурс или привязка будут очищены.

УстановитьТекущееЗначение

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

Принуждение и анимация

Принуждение и анимация работают с базовым значением. Базовое значение — это значение свойства зависимостей с наивысшим приоритетом, определяемым путем оценки вверх по списку приоритетов до достижения элемента 2.

Если анимация не указывает значения обоих From и To свойств для определенных действий, или если анимация намеренно возвращается к базовому значению при завершении, базовое значение может повлиять на анимированное значение. Чтобы увидеть это на практике, запустите пример приложения "Целевые значения ". В примере для высоты прямоугольника попробуйте задать начальные локальные значения, отличающиеся от любого From значения. Примеры анимаций сразу начинают использовать значение From вместо базового значения. Указав Stop в качестве FillBehavior значения, после завершения анимация сбросит значение свойства до его базового уровня. Обычный приоритет используется для определения базового значения после окончания анимации.

К одному свойству можно применять несколько анимаций, причем каждая анимация имеет разные приоритеты. Вместо применения анимации с наивысшим приоритетом обработчик презентации WPF может составить значения анимации в зависимости от того, как были определены анимации и тип анимированных значений. Дополнительные сведения см. в разделе "Обзор анимации"

Приведение находится в верхней части списка приоритетов. Даже запущенная анимация подвержена принудительному приведению к значению. Некоторые существующие свойства зависимостей (dependency properties) в WPF имеют встроенную коэрцию. Для пользовательских свойств зависимостей можно определить поведение приведения, написав метод CoerceValueCallback, который передается в качестве части метаданных при создании свойства. Можно также изменить поведение принуждения для существующих свойств, переопределив метаданные этого свойства в производном классе. Приведение взаимодействует с базовым значением таким образом, чтобы ограничения на приведение применялись так, как они существуют в то время, но базовое значение по-прежнему сохраняется. В результате, если ограничения в приведение будут отменены позже, приведение вернет ближайшее значение к базовому значению, и потенциально влияние приведения на свойство прекратится сразу после отмены всех ограничений. Дополнительные сведения о поведении принуждения см. раздел "Обратные вызовы свойств зависимостей" и "Проверка".

Поведение триггера

Элементы управления часто определяют поведение триггеров в рамках их стиля по умолчанию. Установка локальных свойств для элементов управления может потенциально конфликтовать с этими триггерами, предотвращая реагирование триггеров (визуально или поведенческим образом) на события, управляемые пользователем. Обычное использование триггера свойства заключается в управлении свойствами состояния, такими как IsSelected или IsEnabled. Например, по умолчанию, когда Button отключен, триггер стиля темы (IsEnabled является false) устанавливает значение Foreground, благодаря которому Button отображается серым. Если вы задали локальное значение Foreground, то более высокий приоритет локального значения свойства переопределит значение стиля темы Foreground, даже когда Button отключено. При задании значений свойств, которые переопределяют поведение триггеров уровня темы для элемента управления, не следует не мешать предполагаемому пользовательскому интерфейсу для этого элемента управления.

ClearValue

Метод ClearValue очищает любое локально примененное значение свойства зависимостей для элемента. Но вызов ClearValue не гарантирует, что значение по умолчанию, установленное в метаданных во время регистрации свойств, является новым эффективным значением. Все остальные участники списка приоритетов по-прежнему активны, и удаляется только локально заданное значение. Например, при вызове ClearValue свойства, имеющего стиль темы, значение стиля темы будет применяться в качестве нового значения, а не по умолчанию на основе метаданных. Если вы хотите задать значение свойства для значения зарегистрированных метаданных по умолчанию, получите значение метаданных по умолчанию, запросив метаданные свойства зависимостей, а затем локально задайте значение свойства вызовом SetValue.

См. также