Приоритет значения свойств зависимостей
В этом разделе рассказывается, как работа системы свойств Windows Presentation Foundation (WPF) может повлиять на значение свойства зависимости, и описывается приоритет применения аспектов системы свойств к действительному значению свойства.
Предварительные требования
Предполагается, что вы имеете представление о свойствах зависимости с точки зрения потребителя существующих свойств зависимостей в классах WPF и ознакомились с разделом Общие сведения о свойствах зависимости. Чтобы выполнить примеры в этом разделе, следует также иметь представление о XAML и написании приложений WPF.
Система свойств WPF
Система свойств WPF предлагает эффективный способ определения значений свойств зависимостей с помощью множества факторов, включая такие возможности, как проверка свойства в режиме реального времени, позднее связывание и уведомление связанных свойств об изменениях значений других свойств. Точный порядок и логика, используемые для определения значений свойства зависимости, достаточно сложны. Знание этого порядка поможет избежать ненужной настройки свойств и путаницы в вопросах, почему определенные попытки повлиять на значение свойства зависимости или спрогнозировать его не дали ожидаемого результата.
Свойства зависимостей могут быть "установлены" в нескольких расположениях
Ниже приведен пример XAML где то же свойство (Background) имеет три разных «set» операции, которые могут повлиять на значение.
<Button Background="Red">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Click
</Button>
Как вы считаете, какой цвет будет здесь использован: красный, зеленый или синий?
За исключением динамических значений и приведения наборы локальных свойств устанавливаются с наивысшим приоритетом. Если значение задается локально, можно ожидать, что значение будет соблюдаться, даже если выше все стили и шаблоны элемента управления. В этом примере Background задается значение Red, локально. Таким образом, стиль, определенный в этой области, даже если это неявный стиль, который в противном случае будет применяться ко всем элементам этого типа в этой области, не наивысший приоритет для Background свойства его значение. Если удалить локальное значение Red из этого экземпляра Button, то стиль получит приоритет и кнопка получит значение Background из стиля. Внутри стиля приоритет получают триггеры, поэтому кнопка будет синей, если указатель мыши находится над ней, и зеленым в других случаях.
Список приоритета настройки свойств зависимости
Ниже приведен точный порядок, который использует система свойств при присвоении значений времени выполнения свойствам зависимостей. Сначала указаны элементы с наивысшим приоритетом. Этот список включает некоторые обобщения, сделанные в разделе Общие сведения о свойствах зависимостей.
Приведение системы свойств. Дополнительные сведения о приведении см. в теме Приведение, анимация и базовое значение далее в этом разделе.
Активные анимации или анимации с поведением Hold. Анимация свойства имеет практический эффект только в том случае, если она может иметь приоритет над базовым (неанимированным) значением, даже если это значение было задано локально. Дополнительные сведения см. в теме Приведение, анимация и базовое значение далее в этом разделе.
Локальное значение. Локальное значение может устанавливаться с помощью «оболочки» свойства, которое приравнивается к настройке атрибут или свойство в качестве элемента XAML, или с помощью вызова SetValue API с помощью свойства конкретного экземпляра. Если задано локальное значение с помощью привязки или ресурса, каждый из них функционирует в таком приоритете, как если бы было задано прямое значение.
Свойства шаблона TemplatedParent. Элемент имеет TemplatedParent если она была создана как часть шаблона ( ControlTemplate или DataTemplate). Дополнительные сведения о случаях его применения см. в теме TemplatedParent далее в этом разделе. В шаблоне действует следующий приоритет:
Триггеры — с TemplatedParent шаблона.
Наборы свойств (обычно через XAML атрибуты) в TemplatedParent шаблона.
Неявный стиль. Применяется только к свойству
Style
. СвойствоStyle
заполняется любым ресурсом стиля с ключом, соответствующим типу этого элемента. Ресурс стиля должен существовать либо на странице, либо в приложении; поиск ресурса неявного стиля в темах не выполняется.Триггеры стилей. Триггеры в стилях со страницы или из приложения (эти стили могут быть явными или неявными, но не стилями по умолчанию, поскольку последние имеют более низкий приоритет).
Триггеры шаблонов. Любой триггер из шаблона внутри стиля или непосредственно применяемый шаблон.
Методы задания стилей. Значения из Setter в стилях со страницы или приложения.
Стиль по умолчанию (тема). Подробные сведения о применении этих стилей и связи стилей тем с шаблонами в стилях тем см. в теме Стили (темы) по умолчанию далее в этом разделе. В стиле по умолчанию применяется следующий порядок приоритета:
Активные триггеры в тематическом стиле.
Методы задания в тематическом стиле.
Наследование. Некоторые свойства зависимостей наследуют свои значения от родительского элемента к дочерним элементам, так что их не требуется задавать по отдельности на каждом элементе в приложении. Подробные сведения см. в разделе Наследование значений свойств.
Значение по умолчанию из метаданных свойства зависимости. Любое заданное свойство зависимостей может иметь значение по умолчанию, заданное при регистрации системы свойств конкретного свойства. Кроме того, производные классы, которые наследуют свойства зависимостей, имеют возможность переопределить эти метаданные (включая значение по умолчанию) на уровне отдельных типов. Дополнительные сведения см. в разделе Метаданные свойств зависимостей. Поскольку наследование для наследуемого свойства проверяется до значения по умолчанию, значение по умолчанию родительского элемента имеет приоритет над дочерним элементом. Следовательно, если наследуемое свойство нигде не задано, используется значение по умолчанию, как указано в корневом элементе, либо родительское значение используется вместо значения по умолчанию дочернего элемента.
TemplatedParent
TemplatedParent как приоритетный элемент не применяется ни к какому свойству элемента, объявляемому непосредственно в стандартной разметке приложения. Понятие TemplatedParent существует только для дочерних элементов в пределах визуального дерева, которые создаются в результате применения шаблона. Когда система свойств ищет TemplatedParent шаблона для значения, она ищет шаблон, который создал этот элемент. Значения свойств из TemplatedParent шаблон обычно функционируют, как если бы они были установлены в качестве локальное значение для дочернего элемента, но это имеет меньший приоритет относительно локального значения существует, так как шаблоны являются совместно. Дополнительные сведения см. в разделе TemplatedParent.
Свойство стиля
Порядок поиска, описанный выше ко всем возможным свойствам зависимостей, кроме одного: Style свойство. Style Свойство является уникальным в том, что он стиль невозможно, поэтому элементы приоритета с 5 по 8 не применяются. Кроме того, анимация или приведение Style не рекомендуется (и анимации Style потребует использования пользовательского класса анимации). При этом остается три способа Style свойство может иметь значение:
Явный стиль. Style Свойство задается напрямую. В большинстве случаев стиль не определяется внутри объекта, а используется ссылка на стиль как ресурс с применением явного ключа. В этом случае само свойство Style действует как локальное значение с приоритетом 3.
Неявный стиль. Style Свойство не задано напрямую. Тем не менее Style существует на определенном уровне последовательности поиска ресурсов (страницы, приложения) и шифруется с помощью ключа ресурса, который соответствует является стиль, применяемый к типу. В этом случае Style само свойство действует с приоритетом, определенным в последовательности как элемент 5. Это условие можно обнаружить с помощью DependencyPropertyHelper от Style свойство и ищете ImplicitStyleReference в результатах.
Стиль по умолчанию, также известный как стиль темы. Style Свойство не задается напрямую, а на самом деле оно считывается как
null
времени выполнения. В этом случае стиль поступает из оценки темы времени выполнения, которая является частью механизма презентации WPF.
Для неявных стилей не в темах необходимо точное соответствие - MyButton
Button
-производный класс не будет неявно использовать стиль для Button
.
Стили (темы) по умолчанию
Каждый элемент управления, который поставляется с WPF, имеет стиль по умолчанию. Стили по умолчанию могут варьироваться по темам, поэтому иногда их называют тематическими стилями.
Наиболее важные сведения, находящийся в стиле по умолчанию для элемента управления — его шаблон элемента управления, который существует в тематическом стиле в качестве метода задания для его Template свойство. При отсутствии шаблона из стилей по умолчанию элемент управления без пользовательского шаблона в составе пользовательского стиля вообще бы не имел визуального представления. Шаблон из стиля по умолчанию придает визуальному представлению каждого элемента управления базовую структуру, а также определяет подключения между свойствами, определенными в визуальном дереве шаблона и соответствующем классе элементов управления. Каждый элемент управления предоставляет набор свойств, которые могут повлиять на внешний вид элемента управления без полной замены шаблона. Например, рассмотрим по умолчанию внешний вид Thumb элемент управления, который является компонентом из ScrollBar.
Объект Thumb имеет ряд настраиваемых свойств. Шаблон по умолчанию Thumb создает базовую структуру / визуальное дерево с несколькими вложенными Border компоненты для создания наклона. Если свойство, которое является частью шаблона должно быть предоставлено для настройки с Thumb класса, то это свойство должно быть предоставлено TemplateBinding, в шаблоне. В случае использования Thumb, различные свойства этих границ имеют общую привязку шаблона свойствам, такие как Background или BorderThickness. Однако некоторые другие свойства или визуальные представления заданы в коде шаблона элемента управления или привязаны к значениям, которые поступают непосредственно из темы; чтобы изменить их, необходимо заменить весь шаблон. Как правило, если свойство поступает из шаблонного родительского элемента и не предоставляется привязкой шаблона, его невозможно скорректировать с помощью стилей, поскольку нет простого способа указать его в качестве целевого объекта. Однако это свойство может зависеть от наследования значения свойства в примененном шаблоне или значения по умолчанию.
Тематические стили используют тип в качестве ключа в своих определениях. Тем не менее, при применении тем к экземпляру данного элемента, поиск тем для этого типа выполняется путем проверки DefaultStyleKey свойство элемента управления. Это отличается от сценария неявных стилей, где используется литеральный тип. Значение DefaultStyleKey бы наследуется производными классами, даже если разработчик не изменяет его (рекомендуется изменять свойство не переопределить его на уровне свойств, но чтобы изменить его значение по умолчанию в метаданных свойства). Такая опосредованность позволяет базовым классам определять тематические стили для производных элементов, которые в противном случае не имеют стиля (или, что более важно, не имеют шаблона внутри стиля и поэтому вообще не имеют визуального представления по умолчанию). Таким образом, можно создавать производные MyButton
из Button по-прежнему получите Button шаблон по умолчанию. Если вы были создателем элемента управления MyButton
и требуется другое поведение, можно переопределить метаданные свойства зависимостей для DefaultStyleKey на MyButton
чтобы возвращать другой ключ, а затем определить соответствующие тематические стили, включая шаблон для MyButton
, необходимо упаковать с вашей MyButton
элемента управления. Дополнительные сведения о темах, стилях и создании элементов управления см. в разделе Общие сведения о создании элементов управления.
Ссылки на динамические ресурсы и привязки
В операциях со ссылками на динамические ресурсы и привязками учитывается приоритет расположения при настройке. Например, динамический ресурс, применяемый к локальному значению, действует с приоритетом 3, привязка для метода задания свойства в тематическом стиле действует с приоритетом 9 и так далее. Поскольку ссылки на динамические ресурсы и привязки должны иметь возможность получения значений из состояния времени выполнения приложения, это предполагает, что фактический процесс определения приоритета значения свойства для какого-либо свойства распространяется и на время выполнения.
Ссылки на динамические ресурсы, строго говоря, не являются частью системы свойств, но они имеют свой порядок поиска, который перекликается с вышеуказанной последовательностью. Этот приоритет более подробно описан в разделе Ресурсы XAML. В общем случае действует следующий приоритет: элемент корневой страницы, приложение, тема, система.
Динамические ресурсы и привязки получают приоритет расположения, в котором они были заданы, но значение откладывается. Следствием этого является тот факт, что если задать для динамического ресурса или привязки локальное значение, то при любом изменении локального значения динамический ресурс или привязка будут меняться полностью. Даже если вы вызываете ClearValue метод, чтобы удалить локально заданное значение, динамический ресурс или привязка не будет восстановлено. На самом деле, если вы вызываете ClearValue на свойство, которое имеет динамический ресурс или привязка имея (без литерального локального значения), они также будут удалены с ClearValue вызвать слишком.
SetCurrentValue
SetCurrentValue Метод — еще один способ задать свойство, но не в порядке приоритета. Вместо этого SetCurrentValue позволяет изменить значение свойства, не перезаписывая источник предыдущего значения. Можно использовать SetCurrentValue каждый раз, когда требуется задать значение, не предоставляя этому значению приоритет локального значения. Например, если свойство задается триггером, а затем ему присваивается другое значение с помощью SetCurrentValue, система свойств по-прежнему учитывает этот триггер, и свойство меняется, если происходит действие триггера. SetCurrentValue позволяет изменить значение свойства, не предоставляя ему источник с более высоким приоритетом. Аналогичным образом, можно использовать SetCurrentValue для изменения значения свойства, не перезаписывая привязку.
Приведение, анимации и базовое значение
Приведение и анимация используют значение, которое в SDK определяется как "базовое значение". Базовое значение — это любое значение, определяемое посредством восходящей оценки элементов до тех пор, пока не будет достигнут элемент 2.
Для анимации базовое значение может повлиять на анимированное значение, если анимация не указывает значения From и To для определенных моделей поведения, либо если анимация умышленно возвращается к базовому значению по завершении выполнения. Чтобы увидеть это на практике, запустите Пример целевых значений анимации From, To, By. Попробуйте установить локальные значения высоты прямоугольника в примере, чтобы начальное локальное значение отличалось от любого значения From в анимации. Обратите внимание, что анимация сразу же начинает использовать значения From и заменяет базовое значение после запуска. Анимацию можно указать, чтобы вернуться к значению, обнаруженному перед анимацией после ее завершения, указав Stop FillBehavior. После этого для определения базового значения используется обычный приоритет.
К одному свойству можно применить несколько анимаций, причем каждая из этих анимаций может быть определена в разных точках списка приоритетов значений. Однако вместо того чтобы применять анимацию с более высоким приоритетом, вероятно, анимации объединят свои значения. Это зависит от того, как именно определяются анимации, и от типа анимируемого значения. Дополнительные сведения об анимации свойств см. в разделе Общие сведения об эффектах анимации.
Приведение применяется на самом высоком уровне. Приведение значения может быть выполнено даже для уже выполняющейся анимации. Некоторые существующие свойства зависимостей в WPF имеют встроенные приведения. Для настраиваемого свойства зависимости, для настраиваемого свойства зависимости поведение приведения определяется путем написания CoerceValueCallback и передачи обратного вызова в составе метаданных при создании свойства. Также можно переопределить поведение приведения существующих свойств путем переопределения метаданных для этого свойства в производном классе. Приведение взаимодействует с базовым значением таким образом, что ограничения на приведение применяются в том виде, в котором они существуют на тот момент, однако базовое значение сохраняется. Таким образом, если ограничения в приведении впоследствии будут сняты, приведение вернет ближайшее к базовому возможное значение и, возможно, влияние приведения на свойство прекратится, как только ограничение будет снято. Дополнительные сведения о поведении приведения см. в разделе Проверка и обратные вызовы свойства зависимостей.
Поведения триггера
Элементы управления часто определяют поведение триггера в составе своего стиля по умолчанию, в темах. Установка локальных свойств для элементов управления может препятствовать реагированию триггеров на инициированные пользователями события (визуально или своими действиями). Наиболее распространенное использование триггера свойств предназначен для свойства элемента управления или состояния, например IsSelected. Например, по умолчанию при Button отключена (триггер для IsEnabled — false
) то Foreground значение в тематическом стиле является то, что элемент управления затемнены «». Но если вы задали локальный Foreground значение, что обычный серый цвет будет отменен в приоритете, набора локальных свойств даже в этом сценарии триггера свойства. Будьте осторожны при установке значений для свойств, которые имеют поведения триггеров на уровне темы; кроме того, необходимо убедиться, что не создается ненужных помех работе пользователя с этим элементом управления.
ClearValue и приоритет значения
ClearValue Метод предоставляет соответствующие средства для очистки любого применяемого локально значения из свойства зависимости, которое задается в элементе. Однако, при вызове ClearValue не гарантирует, что новое действительное значение по умолчанию, заданное в метаданных во время регистрации свойства. Все остальные участники в приоритете значений будут по-прежнему активны. Только локально заданное значение удаляется из последовательности приоритетов. Например, если вы вызываете ClearValue по свойству, где этот также задано тематическим стилем, а затем тематическое значение будет применено как новое значение, а не по умолчанию на основе метаданных. Если вы хотите извлечь все элементы значения свойства из процесса и значение по умолчанию зарегистрированные метаданные, можно получить значение по умолчанию точно, путем запроса метаданных свойства зависимостей, а затем можно использовать локально значение по умолчанию свойство с вызовом SetValue.