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


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

В этом разделе описывается система свойств зависимостей, доступная при написании приложения среда выполнения Windows с помощью C++, C#или Visual Basic, а также определений XAML для пользовательского интерфейса.

Что такое свойство зависимостей?

Свойство зависимости — это специализированный тип свойства. В частности, это свойство, в котором значение свойства отслеживается и зависит от выделенной системы свойств, которая является частью среда выполнения Windows.

Для поддержки свойства зависимостей объект, определяющий свойство, должен быть DependencyObject (другими словами, класс, имеющий базовый класс DependencyObject где-то в его наследовании). Многие типы, используемые для определений пользовательского интерфейса для приложения UWP с XAML, будут подклассом DependencyObject и будут поддерживать свойства зависимостей. Однако любой тип, поступающий из пространства имен среда выполнения Windows, у которых нет xaml в его имени, не поддерживает свойства зависимостей. Свойства таких типов являются обычными свойствами, которые не будут иметь поведения зависимостей системы свойств.

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

  • Внешние входные данные, такие как предпочтения пользователя
  • Механизмы определения свойств JIT,такие как привязка данных, анимации и раскадровки
  • Шаблоны шаблонов с несколькими использованием, такие как ресурсы и стили
  • Значения, известные через связи "родительский-дочерний" с другими элементами в дереве объектов

Свойство зависимостей представляет или поддерживает определенную функцию модели программирования для определения приложения среда выполнения Windows с помощью XAML для пользовательского интерфейса и C#, расширений компонентов Microsoft Visual Basic или Visual C++ (C++/CX) для кода. Эти функции включают перечисленные ниже.

  • Привязка данных
  • Стили
  • Раскадровки анимаций
  • Поведение PropertyChanged; Свойство зависимостей можно реализовать для предоставления обратных вызовов, которые могут распространять изменения в другие свойства зависимостей.
  • Использование значения по умолчанию, полученного из метаданных свойства
  • Общая служебная программа системы свойств, например поиск метаданных ClearValue и метаданных

Свойства зависимостей и свойства среда выполнения Windows

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

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

Ниже приведена сумма терминологии, используемой в документации при обсуждении свойств зависимостей:

Срок Description
Свойство зависимостей Свойство, которое существует в идентификаторе DependencyProperty (см. ниже). Обычно этот идентификатор доступен как статический элемент производного класса DependencyObject .
Идентификатор свойства зависимостей Константное значение для идентификации свойства обычно является общедоступным и доступным только для чтения.
Оболочка свойств Вызываемые реализации получения и задания для свойства среда выполнения Windows. Или проекция исходного определения, зависят от языка. Реализация оболочки свойства get вызывает GetValue, передав соответствующий идентификатор свойства зависимостей.

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

В следующем примере определяется настраиваемое свойство зависимостей, определенное для C#, и показано отношение идентификатора свойства зависимостей к оболочке свойства.

public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
  "Label",
  typeof(string),
  typeof(ImageWithLabelControl),
  new PropertyMetadata(null)
);


public string Label
{
    get { return (string)GetValue(LabelProperty); }
    set { SetValue(LabelProperty, value); }
}

Примечание.

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

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

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

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

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

Ниже приведен окончательный порядок использования системой свойств при назначении значения времени выполнения для свойства зависимостей. Сначала указаны элементы с наивысшим приоритетом. Вы найдете более подробные объяснения только после этого списка.

  1. Анимированные значения: активные анимации, анимации визуального состояния или анимации с поведением HoldEnd . Чтобы иметь практический эффект, анимация, применяемая к свойству, должна иметь приоритет над базовым (неанимируемым) значением, даже если это значение было задано локально.
  2. Локальное значение: локальное значение может быть задано с помощью удобства оболочки свойства, которая также соответствует настройке в качестве атрибута или элемента свойства в XAML, или вызовом метода SetValue с помощью свойства определенного экземпляра. Если задать локальное значение с помощью привязки или статического ресурса, каждое действие выполняется в приоритете, как если задано локальное значение, а привязки или ссылки на ресурсы удаляются, если задано новое локальное значение.
  3. Свойства шаблона: элемент имеет эти элементы, если он был создан как часть шаблона (из ControlTemplate или DataTemplate).
  4. Методы задания стилей: значения из метода setter в стилях из ресурсов страницы или приложения.
  5. Значение по умолчанию: свойство зависимостей может иметь значение по умолчанию в составе его метаданных.

Свойства шаблонов

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

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

Примечание.

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

Привязки и приоритет

Операции привязки имеют соответствующий приоритет для любой области, для которую они используются. Например, {Binding}, примененный к локальному значению, действует как локальное значение, а расширение разметки {TemplateBinding} для метода задания свойств применяется в качестве метода задания стиля. Так как привязки должны ждать, пока время выполнения не получит значения из источников данных, процесс определения приоритета значения свойства для любого свойства также расширяется на время выполнения.

Не только привязки работают с тем же приоритетом, что и локальное значение, они действительно являются локальным значением, где привязка является заполнителем для отложенного значения. Если у вас есть привязка для значения свойства, и вы задаете локальное значение во время выполнения, которое полностью заменяет привязку. Аналогичным образом, если вы вызываете SetBinding для определения привязки, которая возникает только во время выполнения, замените любое локальное значение, которое вы могли применить в XAML или ранее выполненный код.

Раскадровка анимаций и базовое значение

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

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

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

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

Дополнительные сведения см. в разделе раскадровки анимаций.

Значения по умолчанию

Определение значения по умолчанию для свойства зависимостей со значением PropertyMetadata подробно описано в разделе свойств настраиваемых зависимостей .

Свойства зависимостей по-прежнему имеют значения по умолчанию, даже если эти значения по умолчанию не были явно определены в метаданных этого свойства. Если они не были изменены метаданными, значения по умолчанию для свойств зависимостей среда выполнения Windows обычно являются одним из следующих:

  • Свойство, использующее объект времени выполнения или базовый тип объекта ( ссылочный тип), имеет значение null по умолчанию. Например, DataContext имеет значение NULL , пока не будет намеренно задано или не наследуется.
  • Свойство, использующее базовое значение, например числа или логическое значение ( тип значения), использует ожидаемое значение по умолчанию для этого значения. Например, 0 для целых чисел и чисел с плавающей запятой, false для логического значения.
  • Свойство, использующее структуру среда выполнения Windows, имеет значение по умолчанию, полученное путем вызова неявного конструктора по умолчанию этой структуры. Этот конструктор использует значения по умолчанию для каждого из основных полей значения структуры. Например, значение по умолчанию для значения point инициализируется со значениями X и Y как 0.
  • Свойство, использующее перечисление, имеет значение по умолчанию первого определенного элемента в этом перечислении. Проверьте ссылку на определенные перечисления, чтобы узнать, что такое значение по умолчанию.
  • Свойство, использующее строку (System.String для .NET, Platform::String для C++/CX), имеет значение по умолчанию пустой строки ("").
  • Свойства коллекции обычно не реализуются как свойства зависимостей, по причинам, рассмотренным далее в этом разделе. Но если вы реализуете свойство пользовательской коллекции и хотите, чтобы оно было свойством зависимостей, обязательно избегайте непреднамеренного одноэлементного, как описано в конце настраиваемых свойств зависимостей.

Функциональные возможности свойства, предоставленные свойством зависимостей

Привязка данных

Свойство зависимостей может задать его значение путем применения привязки данных. Привязка данных использует синтаксис расширения разметки {Binding} в XAML, расширение разметки {x:Bind} или класс привязки в коде. Для свойства для исходящего данных определение конечного значения свойства откладывается до времени выполнения. В то время значение получается из источника данных. Роль, которую играет здесь система свойств зависимостей, обеспечивает поведение заполнителя для операций, таких как загрузка XAML, когда значение еще не известно, а затем предоставляет значение во время выполнения, взаимодействуя с подсистемой привязки данных среда выполнения Windows.

В следующем примере задается значение Text для элемента TextBlock с помощью привязки в XAML. Привязка использует наследуемый контекст данных и источник данных объекта. (Ни один из них не показан в сокращенном примере; более полный пример, показывающий контекст и источник, см. в разделе .Привязка данных в глубине.)

<Canvas>
  <TextBlock Text="{Binding Team.TeamName}"/>
</Canvas>

Можно также установить привязки с помощью кода, а не XAML. См. раздел SetBinding.

Примечание.

Привязки, как это, рассматриваются как локальное значение для целей приоритета значения свойства зависимости. Если задать другое локальное значение для свойства, которое изначально содержало значение привязки , вы полностью перезаписываете привязку, а не только значение времени выполнения привязки. {x:Bind} Привязки реализуются с помощью созданного кода, который задает локальное значение для свойства. Если задать локальное значение для свойства, использующее {x:Bind}, это значение будет заменено при следующем вычислении привязки, например при наблюдении за изменением свойства в исходном объекте.

Источники привязки, целевые объекты привязки, роль FrameworkElement

Чтобы быть источником привязки, свойство не должно быть свойством зависимостей; Обычно любое свойство можно использовать в качестве источника привязки, хотя это зависит от языка программирования, и каждый из них имеет определенные пограничные варианты. Тем не менее, чтобы быть целевым объектом расширения разметки {Binding} или Binding, это свойство должно быть свойством зависимостей. {x:Bind} не имеет этого требования, так как он использует созданный код для применения значений привязки.

Если вы создаете привязку в коде, обратите внимание, что API SetBinding определен только для FrameworkElement. Однако вместо этого можно создать определение привязки с помощью BindingOperations и таким образом ссылаться на любое свойство DependencyObject.

Для кода или XAML помните, что DataContext является свойством FrameworkElement. Используя форму наследования свойств родительского дочернего объекта (как правило, установленного в разметке XAML), система привязки может разрешить DataContext , который существует в родительском элементе. Это наследование может оценить, даже если дочерний объект (который имеет целевое свойство) не является FrameworkElement и поэтому не содержит собственного значения DataContext. Однако родительский элемент, наследуемый, должен быть FrameworkElement для задания и хранения DataContext. Кроме того, необходимо определить привязку таким образом, что она может функционировать с значением NULL для DataContext.

Подключение привязки — это не единственное, что необходимо для большинства сценариев привязки данных. Чтобы односторонняя или двусторонняя привязка была эффективной, исходное свойство должно поддерживать уведомления об изменениях, которые распространяются в систему привязки и таким образом целевой объект. Для пользовательских источников привязки это означает, что свойство должно быть свойством зависимостей, или объект должен поддерживать INotifyPropertyChanged. Коллекции должны поддерживать INotifyCollectionChanged. Некоторые классы поддерживают эти интерфейсы в их реализации, чтобы они были полезны в качестве базовых классов для сценариев привязки данных; Пример такого класса — ObservableCollection<T>. Дополнительные сведения о привязке данных и о том, как привязка данных связана с системой свойств, см . в подробной статье о привязке данных.

Примечание.

Перечисленные здесь типы поддерживают источники данных Microsoft .NET. Источники данных C++/CX используют различные интерфейсы для уведомления об изменении или наблюдаемого поведения, см . подробные сведения о привязке данных.

Стили и шаблоны

Стили и шаблоны — это два сценария для свойств, определенных как свойства зависимостей. Стили полезны для задания свойств, определяющих пользовательский интерфейс приложения. Стили определяются как ресурсы в XAML либо как запись в коллекции ресурсов , либо в отдельных файлах XAML, таких как словари ресурсов темы. Стили взаимодействуют с системой свойств, так как они содержат методы задания свойств. Самым важным свойством здесь является свойство Control.Template элемента Управления: оно определяет большую часть визуального вида и визуального состояния элемента управления. Дополнительные сведения о стилях и некоторых примерах XAML, определяющих стиль и использующих методы задания, см. в элементах управления Styling.

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

Раскадровки анимаций

Вы можете анимировать значение свойства зависимостей с помощью раскадровки анимации. Раскадровки анимаций в среда выполнения Windows не просто визуальные украшения. Более полезно рассматривать анимацию как метод компьютера состояния, который может задавать значения отдельных свойств или всех свойств и визуальных элементов элемента управления, а также изменять эти значения с течением времени.

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

Если анимация применяется и выполняется, анимированное значение работает с более высоким приоритетом, чем любое значение (например, локальное значение), которое имеет свойство в противном случае. Анимации также имеют необязательное поведение HoldEnd , которое может привести к применению анимации к значениям свойств, даже если анимация визуально останавливается.

Принцип компьютера состояния реализуется с помощью раскадровки анимаций в рамках модели состояния VisualStateManager для элементов управления. Дополнительные сведения о раскадровке анимаций см. в разделе Раскадровки анимаций. Дополнительные сведения о VisualStateManager и определении визуальных состояний для элементов управления см. в разделе "Раскадровки анимаций" для визуальных состояний или шаблонов элементов управления.

Поведение, измененное свойством

Поведение, измененное свойством, является источником терминологии свойств зависимости. Сохранение допустимых значений для свойства, когда другое свойство может повлиять на значение первого свойства, является сложной проблемой разработки во многих платформах. В системе свойств среда выполнения Windows каждое свойство зависимостей может указывать обратный вызов, который вызывается всякий раз, когда его значение свойства изменяется. Этот обратный вызов можно использовать для уведомления или изменения связанных значений свойств, как правило, синхронно. Многие существующие свойства зависимостей имеют измененное свойство поведение. Вы также можете добавить аналогичное поведение обратного вызова в настраиваемые свойства зависимостей и реализовать собственные обратные вызовы, измененные свойством. Пример см . в свойствах настраиваемых зависимостей .

В Windows 10 представлен метод RegisterPropertyChangedCallback. Это позволяет коду приложения регистрировать уведомления об изменениях при изменении указанного свойства зависимостей в экземпляре DependencyObject.

Значение по умолчанию и ClearValue

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

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

DependencyObject и потоки

Все экземпляры DependencyObject должны быть созданы в потоке пользовательского интерфейса, связанном с текущим окном, которое отображается приложением среда выполнения Windows. Хотя каждый объект DependencyObject должен быть создан в основном потоке пользовательского интерфейса, объекты можно получить с помощью ссылки диспетчера из других потоков, доступ к свойству Диспетчера . Затем можно вызвать такие методы, как RunAsync в объекте CoreDispatcher, и выполнить код в правилах ограничений потоков в потоке пользовательского интерфейса.

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

Концептуальный материал