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


Приоритет значения свойств зависимостей

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

В этом разделе содержатся следующие подразделы.

  • Предварительные требования
  • Система свойств WPF
  • Свойства зависимостей могут быть "установлены" в нескольких местах
  • Список приоритетов параметров свойства зависимостей
  • TemplatedParent
  • Свойство Style
  • Стили по умолчанию (тематические).
  • Привязка и ссылки на динамические ресурсы
  • SetCurrentValue
  • Приведение, анимация и базовое значение
  • Поведения триггера
  • Приоритет значений и ClearValue
  • Связанные разделы

Предварительные требования

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

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

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

Свойства зависимостей могут быть "установлены" в нескольких местах

Ниже приведен пример XAML, где одно и то же свойство (Background) имеет три различные операции "установки", которые могут повлиять на значение.

    <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 из стиля. Внутри стиля приоритет получают триггеры, поэтому кнопка будет синей, если указатель мыши находится на ней. В противном случае кнопка будет зеленой.

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

Ниже приведен точный порядок, который использует система обработки свойств при присваивании значений свойств зависимостей во время выполнения. Первым указан наиболее приоритетный параметр. Этот список включает некоторые обобщения, сделанные в Общие сведения о свойствах зависимости.

  1. Приведение системы свойств. Сведения о приведении см. в подразделе Приведение, анимация и базовое значение данного раздела.

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

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

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

    1. Триггеры из шаблона TemplatedParent.

    2. Свойство задается (обычно через атрибуты XAML) в шаблоне TemplatedParent.

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

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

  7. Триггеры шаблона. Любой триггер из шаблона внутри стиля или непосредственно применяемый шаблон.

  8. Способы установки стиля. Значения из Setter внутри стилей из страницы или приложения.

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

    1. Активные триггеры в тематическом стиле.

    2. Способы установки в тематическом стиле.

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

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

TemplatedParent

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

Свойство Style

Порядок поиска, описанный выше, применяется ко всем возможным свойствам зависимостей, за исключением свойства 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 в элементе управления. В неявных стилях, в свою очередь, используется литерал Type. Значение DefaultStyleKey наследуется производными классами, даже если разработчик не изменяет его (рекомендуется изменять свойство, не переопределяя его на уровне свойства, а изменяя его значение по умолчанию в метаданных свойства). Это позволяет базовым классам определять тематические стили для производных элементов, которые в противном случае не имеют стиля (или, что более важно, не имеют шаблон внутри стиля и поэтому не имеют по умолчанию визуального представления). Таким образом, можно получать производный элемент MyButton из Button и по-прежнему использовать шаблон по умолчанию Button. Если при создании элемента управления MyButton требуются различные варианты поведения элемента, можно переопределить метаданные свойства зависимостей для DefaultStyleKey в элементе MyButton, чтобы он возвращал другой ключ, а затем определить подходящие тематические стили, включая шаблон для MyButton, который нужно включить в комплектацию элемента управления MyButton. Дополнительные сведения о темах, стилях и элементах управления см. в разделе Общие сведения о разработке управления.

Привязка и ссылки на динамические ресурсы

Ссылки на динамические ресурсы и операции привязки учитывают приоритет расположения, в котором они заданы. Например, динамический ресурс, примененный к локальному значению, действует как элемент с приоритетом 3, привязка для метода задания свойства внутри тематического стиля применяется как элемент с приоритетом 9 и т. д. Поскольку ссылки на динамические ресурсы и привязка должны иметь возможность получения значений из состояния времени выполнения приложения, фактический процесс определения приоритета значения свойства для любого заданного свойства также расширяется во времени выполнения.

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

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

SetCurrentValue

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

Приведение, анимация и базовое значение

Приведение и анимация используют значение, которое определяется как "базовое значение" для всего SDK. Таким образом, базовым значением является любое значение, определяемое с помощью оценки элементов от менее приоритетного к более приоритетному, пока не будет достигнут элемент 2.

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

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

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

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

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

Приоритет значений и ClearValue

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

См. также

Ссылки

DependencyObject

DependencyProperty

Основные понятия

Общие сведения о свойствах зависимости

Пользовательские свойства зависимостей

Проверка и обратные вызовы свойства зависимостей