DependencyProperty в Silverlight
Пред-история
Система с getter-ами и setter-ами из .NET-a представляет собой значительное улучшение метода работы с классами и обьектами из Visual C++, по простой причине что позволяет выполнять произвольный код в момент изменения или чтения значения свойства.
Два классичеких примера использования:
- Перерисовка окна в момент изменения свойств Width, Height, Background, и др.
- Валидация значения свойства в setter-е
Что такое DependencyProperty?
Практически, свойства в .NET-е всего-лишь метод оповестить объект свойство которого мы изменяем. DependencyProperty берут эту идею и ведут её дальше, оповещая весь WPF о изменении свойства.
Что-бы понять DependencyProperty, надо понять концепт визуального дерева из WPF (WPF visual tree). Практически, весь интерфейс организован внутренне в виде арборесцентной структуры, похожую на DOM из HTML.
Контроли в Silverlight состоят из геометрических фигур (изогнутых линии) и контейнеров, так что и всё дерево состоит из контейнеров и геометрических фигур. В отличие от WindowsForms, содержание многих контролей можно в корни изменить с помощью шаблонов, следовательно, у нас есть контроли, которые различаются от стандартного вида на все 100%. Рассмотрим следующий пример: Grid содержит кнопку, которая, в свою очередь, содержит изображение и текст (одно из лучших особенностей Silverlight является возможность некоторых контролей, таких как кнопки или комбобоксы, содержать другие визуальные элементы). Когда ширина кнопки меняется программно, оно уведомляет об изменении так Grid как и контроли содержащиеся в кнопке, которые в свою очередь могут принять решение о перерисовке.
Стоит заметить что чаще всего значение которое мы хотим присвоить DependenyProperty, не будет и значением которое будет на самом деле присвоено. Например, если мы присвоим ширине кнопки н-ное значение, оно может быть ограничено максимальным размером сетки, или рядом других факторов. Практически название DependencyProperty говорит само за себя – и означает то что фактическое значение свойства зависит от многих факторов. Среди факторов, которые действуют на значение DependencyProperty, можно привести, в порядке приоритета:
- Внутренняя система корекции значений
- Активная анимация, которая работает со свойством
- Желаемое значение
- Шаблон используемый свойством
- Стиль используемый контролем
- Значение по умолчанию
Можно заметить что желаемое значение находится всего на 3-м месте в списке. Это случается потому что желаемое значение которое проходит через валидацию и корекцию в соответствии с другими свойствами.
Пример
Что-бы обьект мог использовать DependencyProperty он должен наследовать его у DependencyObject.
public class MyClass: DependencyObject { public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register("IsSpinning", typeof(Boolean), typeof(MyClass), new PropertyMetadata(MyClass.IsSpinningPropertyValueChanged)); public bool IsSpinning { get { return (bool)GetValue(IsSpinningProperty); } set { SetValue(IsSpinningProperty, value); } } private static void IsSpinningPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MyClass myClass = (MyClass)d; // валидация } }
http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx
Замечания:
- Класс содержащий DependencyProperty должен наследовать от DependencyObject
- При этом он создает статическое свойство, DependencyProperty MyProperty
- Свойство регистрируется в системе WPF с помощью статического метода DependencyProperty.Register()
- Для удобства использования, статическое свойство упаковано. В getter-е и setter-е используются унаследованные от DependencyObject методы GetValue() и SetValue().