Свойства зависимости
66WPF --- Основа WPF --- Свойства зависимости
Подобно любому API-интерфейсу .NET, внутри реализации WPF используются все члены системы типов .NET (классы, структуры, интерфейсы, делегаты, перечисления) и каждый член типа (свойства, методы, события, константные данные, поля только для чтения и т.п.). Однако WPF также поддерживает уникальную программную концепцию под названием свойства зависимости (dependency property).
Свойства зависимости являются совершенно новой, значительно более полезной, реализацией свойств. Без них вы не сможете работать с основными средствами WPF, такими как анимация, привязка данных и стили.
Большинство свойств у элементов WPF являются свойствами зависимости. Во всех примерах, которые были приведены до настоящего момента, вы использовали свойства зависимости, даже не подозревая об этом. Это объясняется тем, что свойства зависимости разработаны таким образом, чтобы с ними можно было работать как с обычными свойствами.
И все же свойства зависимости не являются обычными свойствами. Лучше всего представлять себе эти свойства как обычные (определяемые в .NET обычным образом), но с дополнительным набором возможностей WPF. В концептуальном отношении поведение свойств зависимости не отличается от поведения обычных свойств, однако реализованы они по-другому. Причина проста: производительность. Если бы разработчики WPF просто внесли дополнительные возможности в систему свойств .NET, то им пришлось бы создать сложный и громоздкий слой для вашего кода. Рядовые свойства не могут поддерживать все характеристики свойств зависимости, не перегружая при этом систему.
Свойства зависимости являются специфическим детищем WPF. Однако в библиотеках WPF они всегда заключены в оболочки обычных процедур свойств .NET. Это позволяет использовать их обычным образом даже в том коде, который не имеет понятия о системе свойств зависимости WPF. На первый взгляд странно, что новая технология упакована в старую, однако только так WPF может изменить такой фундаментальный ингредиент, как свойства, не нарушая структуру остального мира .NET.
Подобно "нормальному" свойству .NET (которое в литературе, посвященной WPF, часто называют свойством CLR (CLR property)), свойства зависимости могут устанавливаться декларативно, с использованием XAML или программно в файле кода. Более того, свойства зависимости (подобно свойствам CLR) в конечном итоге предназначены для инкапсуляции полей данных класса и могут быть сконфигурированы как доступные только для чтения, только для записи или для чтения и записи.
Что более интересно: почти в любом случае вы будете пребывать в счастливом неведении относительно того, что на самом деле устанавливаете (или читаете) свойство зависимости, а не свойство CLR! Например, свойства Height и Width, которые элементы управления WPF наследуют от FrameworkElement, а также член Content, унаследованный от ControlContent — все это фактически свойства зависимости:
<!-- Установить три свойства зависимости -->
<Button х:Name = "btnMyButton" Height = "50" Width = "100" Content = "OK"/>
С учетом всех этих сходств возникает вопрос: зачем нужно было определять в WPF новый термин для такой знакомой концепции? Причина кроется в способе реализации свойства зависимости внутри класса. На высшем уровне все свойства зависимости создаются следующим образом:
Прежде всего, класс, определяющий свойство зависимости, должен иметь в своей цепочке наследования DependencyObject.
Единственное свойство зависимости представляется как общедоступное, статическое, предназначенное только для чтения поле в классе типа DependencyProperty. По существующему соглашению имя этого поля формируется добавлением слова Property к имени оболочки CLR.
Переменная DependencyProperty зарегистрирована с помощью статического вызова DependencyProperty.Register(), что обычно происходит в статическом конструкторе или встроенным образом, при объявлении переменной.
Наконец, класс определит дружественное к XAML свойство CLR, которое осуществляет вызовы методов, предоставленных DependencyObject, для получения и установки значения.
Будучи реализованными, свойства зависимости представляют множество мощных средств, используемых различными технологиями WPF, включая привязку данных, службы анимации, стили и т.д. В основе своей мотивация свойств зависимости заключается в предоставлении способа вычисления значения свойства на основе значений других источников. Ниже приведен список некоторых основных преимуществ, которые выходят за рамки простой инкапсуляции данных, имеющейся в свойстве CLR:
Свойства зависимости могут наследовать свои значения от XAML-определения родительского элемента. Например, если вы определите значение атрибута FontSize в открывающем дескрипторе <Window>, то все элементы управления в этом Window будут по умолчанию иметь этот размер шрифта.
Свойства зависимости поддерживают возможность иметь значения, установленные элементами, находящимися в области видимости XAML, такие как установка Button свойства Dock родительской DockPanel.
Свойства зависимости позволяют WPF вычислять значение на основе нескольких внешних значений, что может быть очень важно для анимации и служб привязки данных.
Свойства зависимости предоставляют инфраструктуру поддержки для триггеров WPF (так же довольно часто используемых при работе с анимацией и привязкой данных).
Запомните, что во многих случаях вы будете взаимодействовать с существующим свойством зависимости в манере, идентичной нормальному свойству CLR (благодаря оболочке XAML).