uzluga.ru
добавить свой файл



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 могут иметь различные модификаторы доступа для чтения и записи (т.н. readonly DependencyProperty)



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 нельзя изменять



Наследники PropertyMetadata

  • UIPropertyMetadata – наследник PropertyMetadata, позволяющий задавать, может ли свойство быть анимировано

  • FrameworkPropertyMetadata – наследник UIPropertyMetadata, позволяющий задавать метаданные, имеющие смысл в контексте дерева элементов WPF

    • Нужно ли перерисовать объект при изменении свойства
    • Влияет ли свойство на размеры объекта и его положение, на размеры и положение родителя
    • Является ли значение свойства наследуемым
    • Поддерживает ли свойство биндинг
    • Является ли двусторонний биндинг биндингом по умолчанию


Наследование DependencyProperty

  • Метод DependencyProperty.OverrideMetadata позволяет переопределять метаданные для классов-потомков

    • Переопределение должно быть сделано до создания первого экземпляра класса
    • Переопределить DependencyProperty можно не более одного раза для каждого типа
  • Метод DependencyProperty.AddOwner позволяет связать свойство с классом вне иерархии наследования

    • AddOwner также позволяет переопределить метаданные
    • DependencyProperty, связанное с несколькими независимыми классами, выполняет функцию контракта (аналог интерфейса)


AttachedProperty

  • Концепция XAML, позволяющая в одном элементе указывать значение для свойства, определенного в другом

  • В 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 readonly DependencyProperty NameProperty =

DependencyProperty.RegisterAttached("Name",

typeof(propType), typeof(ownerType));

static propType GetName(object element){}

static void SetName(object element, propType arg){}

Extend with Attached

  • Механизм AttachedProperties позволяет добавить к любому наследнику DependencyObject новые свойства

  • Уникальность свойств (в том числе приватных) гарантируется за счет компоненты OwnerType

  • Исходя из изменения AttachedProperties, можно реализовать любую дополнительную логику для объекта

    • При этом можно сохранять все необходимые для выполнения логики данные в самом объекте
  • Логика может включать порождение событий, реализованных с помощью AttachedEvents



Ссылки

http://www.codeplex.com/wpf

Спасибо!