190 likes | 442 Views
DependencyObject и DependencyProperty. Александр Шер Разработчик ЗАО «Айко». О чем пойдет речь?. DependencyObject Dispatcher DependencyProperty AttachedProperty Метаданные Расширение функциональности существующих контролов. DependencyObject. «Самый базовый класс» в WPF
E N D
DependencyObjectи DependencyProperty Александр Шер Разработчик ЗАО «Айко»
О чем пойдет речь? • DependencyObject • Dispatcher • DependencyProperty • AttachedProperty • Метаданные • Расширение функциональности существующих контролов
DependencyObject • «Самый базовый класс» в WPF • Является базовым для классов Visual,ContentElement, TriggerBaseи InputBinding • Использует DependencyProperty • Получение/изменение значения • Получение списка всех измененных DependencyProperty • Перехват изменений значений • Информирует биндинги об изменении значения DependencyProperty • Отслеживает, чтобы обращение к DependencyProperty было только из потока, создавшего DependencyObject
Dispatcher • Dispatcher – это расширенный вариант очереди сообщений с приоритетом • Делегаты помещаются в очередь и вызываются согласно приоритету и порядку в очереди • Каждый Dispatcher связан с определенным потоком • Все делегаты вызываются последовательно в одном потоке • С помощью Dispatcher’а можно передать выполнение метода в другой поток, в том числе синхронно (аналогjoin) • В Dispatcher UI потока попадает весь пользовательский ввод (мышь, клавиатура и т.п.)с наивысшим приоритетом • Каждый DependencyObjectсвязан с Dispatcher’ом потока, в котором он был создан
Приоритеты Dispatcher • Foreground-приоритеты • Send = 10 – сообщения Windows (в т.ч. пользовательский ввод) • Normal = 9 – значение по-умолчанию • DataBind = 8 – связывание данные и сопутствующие процессы • Render = 7 – отрисовка • Loaded = 6 – сразу после отрисовки (событие Loaded) • Background-приоритеты • Input = 5 – выполняется только после пользовательского ввода • Background = 4 – последний из «активных» приоритетов • Idle-приоритеты • ContextIdle = 3 • ApplicationIdle = 2 • SystemIdle = 1 • Inactive
DependencyProperty • DependencyProperty – объект, используемый в качестве ключа для хранения значений свойств в словаре DependencyObject • В одном приложении может быть создано не более 65536 экземпляров DependencyProperty • DependencyProperty определяется для типа, но используется в экземпляре • Как правило, экземпляры DependencyProperty определяются как статические readonlyполянаследника DependencyObject • Нельзя определитьстатическое свойство, использующее DependencyProperty • DependencyPropertyмогут иметь различные модификаторы доступа для чтения и записи (т.н.readonlyDependencyProperty)
DependencyProperty • Для чего нужны DependencyProperty: • Получение значения через Binding • Сеттеры в стилях • Пути в биндингах и триггерахдля источника (с отслеживанием изменений) • Единый механизм проверки и перехвата изменения значений • DependencyPropertyиспользуется WPF напрямую! • Т.е. в обход обертки-свойства экземпляра • DependencyProperty.UnsetValue – значение, указывающее, что DependencyPropertyне менялось или было очищено (вызовом метода ClearValue) • Аналог undefined в javascript
Регистрация DependencyProperty • Для создания DependencyProperty используется статический метод DependencyProperty.Registerсо следующими параметрами • name (String) – имя DependencyProperty, как правило, совпадает с именем свойства-обертки экземпляра класса • propertyType (Type) – тип свойства, как правило, совпадает с типом свойства-обертки • ownerType (Type) – тип объекта, для которого регистрируется свойство • propertyMetadata (необязательное, PropertyMetadata) – дополнительные сведения о свойстве, метаданные • validateValueCallback (необязательное, ValidateValueCallback) – метод, валидирующий задаваемое значение (неверное значение приводит к исключению!) • Параметры name и ownerTypeобразуют уникальный ключ
PropertyMetadata • DependencyProperty при регистрациипозволяют задавать метаданные, которые могут • Контролировать и оповещать об изменениях значений свойства • Определять влияние свойства на объект и его окружение • Наделять свойство общей для всех экземпляров класса логикой • Базовый класс PropertyMetadataпозволяет задать • Дефолтное значение свойства • Методкорректировки нового значения (CoerceValueCallback) • Метод перехвата изменения значения (PropertyChangedCallback) • DependencyProperty в общем случае не подчиняются правилу для свойств «записанное значение равно считанному» • Ввиду наличия метода корректировки нового значения
PropertyMetadata • Наследники PropertyMetadataмогут определять свою дополнительную логику для свойств • Применение к конкретному типу описывается в методе OnApply • Класс PropertyMetadataпозволяет переопределять изначальные метаданные DependencyProperty • Логика переопределения описывается в методе Merge • После регистрации DependencyPropertyсвязанный с ним класс PropertyMetadataнельзя изменять • Наследники должны придерживаться этой логики, проверяя свойство IsSealed
Наследники PropertyMetadata • UIPropertyMetadata – наследник PropertyMetadata, позволяющий задавать, может ли свойство быть анимировано • FrameworkPropertyMetadata – наследник UIPropertyMetadata, позволяющий задавать метаданные, имеющие смысл в контексте дерева элементов WPF • Нужно ли перерисовать объект при изменении свойства • Влияет ли свойство на размеры объекта и его положение, на размеры и положение родителя • Является ли значение свойства наследуемым • Поддерживает ли свойство биндинг • Является ли двусторонний биндинг биндингом по умолчанию
Наследование DependencyProperty • Метод DependencyProperty.OverrideMetadataпозволяет переопределять метаданные для классов-потомков • Переопределение должно быть сделано до создания первого экземпляра класса • Переопределить DependencyPropertyможно не более одного раза для каждого типа • Метод DependencyProperty.AddOwnerпозволяет связать свойство с классом вне иерархии наследования • AddOwnerтакже позволяет переопределить метаданные • DependencyProperty, связанное с несколькими независимыми классами, выполняет функцию контракта (аналог интерфейса)
AttachedProperty • Концепция XAML, позволяющая в одном элементе указывать значение для свойства, определенного в другом • <TextBlockDockPanel.Dock="Top" … • В WPF AttachedProperty – подвид DependencyProperty • AttachedPropertyне связано с конкретным типом DependencyObject • Использование AttachedProperty похоже на работу с парой статических методов • AttachedPropertyможет быть использовано тремя различными способами • Свойства задаются у дочерних элементов (Grid.Row) • Свойство задается у родителя (ScrollViewer.CanContentScroll) • Свойство задается где угодно, а owner является «сервисом» (PresentationTraceSources.TraceLevel)
Особенности AttachedProperty • Тип ownerType при регистрации AttachedPropertyявляется только частью ключа • AttachedPropertyможно использовать для разных типов • В метод PropertyMetadata.OnApplyпередаетсяtargetType==null • AttachedPropertyимеет определенную сигнатуру, необходимую для использования из XAML static readonlyDependencyPropertyNameProperty = DependencyProperty.RegisterAttached("Name", typeof(propType), typeof(ownerType)); staticpropTypeGetName(object element){} staticvoidSetName(object element, propTypearg){}
Extend with Attached • Механизм AttachedPropertiesпозволяет добавить к любому наследнику DependencyObjectновые свойства • Уникальность свойств (в том числе приватных) гарантируется за счет компоненты OwnerType • Исходя из изменения AttachedProperties, можно реализовать любую дополнительную логику для объекта • При этом можно сохранять все необходимые для выполнения логики данные в самом объекте • Логика может включать порождение событий, реализованных с помощью AttachedEvents
Ссылки • Раздел, посвященный WPF в MSDN:http://msdn.microsoft.com/wpf • WPF на CodePlex: http://www.codeplex.com/wpf • Собрание блоггеров (Dr. WPF, John Smith, Beatriz Costa, etc.):http://wpfdisciples.wordpress.com/