140 likes | 297 Views
Классы Windows Presentation Foundation. Модели пользовательских элементов управления. WPF предоставляет три программных модели для создания пользовательских элементов управления :
E N D
Модели пользовательских элементов управления • WPF предоставляет три программных модели для создания пользовательских элементовуправления: • Элементы управления, использующие базовый класс UserControl, представляют собой контейнеры из существующих элементов управления. Эти элементы не поддерживает настройку с помощью DataTemplate или ControlTemplate. • Пользовательские элементы управления на базе класса Controlсвое визуальное представление определяют при помощи шаблонов. Это позволяет отделить рабочую логику от визуального представления элемента. • Элементы управления, использующие в качестве непосредственного базового класса FrameworkElement, сами выполняют отрисовку.
Свойства зависимостей пользовательского элемента управления • В пользовательском элементе управления можно зарегистрировать собственные свойства зависимостей, что дает возможность работать с ними так же, как и со свойствами любого элемента управления, поставляемого с WPF, в частности, можно • задать значение свойства в стиле; • выполнить привязку свойства к источнику данных; • как значение свойства использовать динамическийресурс; • выполнить анимацию для свойства; • унаследовать значение свойства от родительского элемента в дереве элементов ( в этом случае необходима регистрация с помощью метода RegisterAttached); • получать уведомление от системы свойств WPF об изменении значения свойства.
Регистрация свойства зависимостей пользовательского элемента управления • Свойство зависимостей регистрируется с помощью метода Registerкласса DependencyProperty. Метод добавляет запись в таблице, которая поддерживается системой свойств WPF, и предоставляет свойству уникальный идентификатор. Этот идентификатор сохраняется в поле publicstaticreadonlyтипа DependencyProperty как часть класса и используется в последующих операциях системы свойств. • В примере в классе CityComboBoxрегистрируется свойство CityProperty: class CityComboBox : ComboBox { privatestaticstring[] CityList = { "Москва", "Петербург", "Новгород" }; public static readonlyDependencyPropertyCityProperty; static CityComboBox() { FrameworkPropertyMetadata fpm = new FrameworkPropertyMetadata( CityList[0], // Default new PropertyChangedCallback(OnCityChanged)); fpm.BindsTwoWayByDefault = true; CityProperty = DependencyProperty.Register("City", typeof(string), typeof(Wpf_UserControls.CityComboBox), fpm, ValidateCityCallback); } […code…] }
Соглашения об имени свойств зависимостей • Существуют соглашения об именахдля свойств зависимостей. • Свойство зависимости имеет базовое имя — в примере это “City” (первый параметр метода Register). • Имя для поля идентификатора свойства создается путем добавления суффикса Property к имени свойства – в примере это “CityProperty”. Это имя используется в вызовах методов SetValue и GetValue класса DependencyObjectкак в коде приложения, так и в вызовах системы свойств WPF. • Можно определить свойства CLR get/set,которые не должны выполнять никакой обработки значений свойства зависимости, кроме вызовов GetValue и SetValue, так как система свойств WPF может вызывать методы GetValue и SetValue напрямую. • Имя свойства CLR должно совпадать с именем, которое передается при регистрации как первый параметр метода Register. В примере определено свойство CLR для свойства зависимости CityProperty public string City { get { return (string)this.GetValue(CityProperty); } set {this.SetValue(CityProperty, value); } } • Если выполнены не все соглашения об именах свойства зависимости, это может привести к проблемам при работе с ним, так как большинство инструментов предполагает выполнение этих правил именования объектов, связанных со свойством зависимости.
Метаданные свойства зависимости • При регистрации свойства зависимостей можно задать некоторые характеристики свойства, используя объект класса PropertyMetadata (или производного класса ). • Часть характеристик можно задать в конструкторах классов, другие передаются через свойства объекта PropertyMetadata с доступом { get; set}. Метаданные нельзя изменить после регистрации свойства зависимостей. • Конструкторы для метаданных с максимальным числом параметров public PropertyMetadata ( Object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback ); public UIPropertyMetadata ( Object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, boolisAnimationProhibited ); public FrameworkPropertyMetadata( Object defaultValue, FrameworkPropertyMetadataOptions flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, boolisAnimationProhibited, UpdateSourceTrigger defaultUpdateSourceTrigger );
Некоторые свойствакласса FrameworkPropertyMetadata • Некоторые свойства , например DefaultValue, имеют доступ { get; set; }. Значения этих свойств можно изменить после их инициализации в конструкторе. • После регистрации свойства зависимостей с помощью методов Register, AddOwner или OverrideMetadata объект с метаданными становится неизменяемым.
Проверка и обратные вызовы свойства зависимостей • Проверка корректности значения свойства зависимости выполняется в отдельном методе, а не в упаковщиках свойства { get; set}, так как • код WPF может вызвать методы SetValue или GetValueнапрямую без вызова { get; set}; • значение может зависеть от других объектов, например, свойство может унаследовать свое значение через дерево элементов или получить его в результате привязки данных. • При регистрации свойства зависимости можно определить ссылки на реализации методов обратного вызова с делегатами • ValidateValueCallback – для проверки значения свойства; • CoerceValueCallback – для приведения (coerce) значения свойства; • PropertyChangedCallback - метод обратного вызова при изменении значения свойства. • Методы обратного вызова работают в следующем порядке: • ValidateValueCallback • CoerceValueCallback • PropertyChangedCallback
ValidateValueCallback • Для проверки значения свойства зависимости для класса можно определить отдельный метод с сигнатурой, отвечающей делегату ValidateValueCallback public delegate bool ValidateValueCallback( Object value ); • Метод выполняет пользовательскую проверку значения свойства зависимостей после обычной проверки типа, и должен возвращать значение true, если значение свойства допустимо, и falseв противном случае. Метод не выполняет корректировку значения свойства – новое значение принимается или нет. • Обратный вызов проверки значения вызывается системой свойств WPF, в частности при инициализации значением по умолчанию и при вызове SetValue. Если при этом возвращается значение false, бросается исключение, которое должно быть обработано приложением. • Обратный вызов проверки значения не содержит ссылки на экземпляр DependencyObject, для которого устанавливается значение свойства, он проверяет значение для класса, а не для конкретного экземпляра класса. • Возможность изменить значение свойства при проверке предоставляют методы обратного вызова CoerceValueCallback и PropertyChangedCallback. • Метод ValidateValueCallbackуказывается как параметр в методе Register при регистрации свойства зависимости, не является частью метаданных свойства, и не может быть переопределен после регистрации свойства.
CoerceValueCallback • Метод обратного вызова, который можно использовать для анализа допустимости значения свойства зависимостей для конкретного объекта, имеет тип CoerceValueCallback: public delegate Object CoerceValueCallback(DependencyObjectdobj, Object baseValue ); • Метод CoerceValueCallbackполучает два параметра – новое значениесвойства и объект, к которому оно применяется. Метод вызывается до изменения значения свойства, старое значение свойства доступно через объект dobj. • Так как метод CoerceValueCallbackимеет доступ к объектуdobj, для которого проверяется значение свойства, его удобно использовать при работе со свойствами, значения которых взаимосвязаны. • Метод обратного вызова CoerceValueCallback для свойства зависимостей вызывается в результате явного или неявного вызова метода CoerceValue из класса DependencyObject. public void CoerceValue ( DependencyPropertydp );
PropertyChangedCallback • Делегат PropertyChangedCallbackопределяет тип методаобратного вызова, который инициируется при изменении действующего значения свойства зависимостей: public delegate void PropertyChangedCallback( DependencyObjectdobj, DependencyPropertyChangedEventArgs e ); • В классе DependencyPropertyChangedEventArgs, объект которого передаетсячерез второй параметр, определены свойства • В методе можно инициировать событие изменения значения свойства, если эта информация полезна другим классам.
Виртуальный метод OnPropertyChanged • В классе DependencyObject определен виртуальный метод OnPropertyChanged, который вызывается при обновлении значения любого свойства зависимостей в объекте DependencyObject. • Через параметры метода система свойств WPF передает свойство зависимости, которое изменяется, а также старое и новое значения свойства. protected virtual void OnPropertyChanged( DependencyPropertyChangedEventArgs e ); • Так как метод OnPropertyChanged вызывается при изменении значения любого свойства зависимостей, он выполняется много раз в течение времени существования объекта. • Метод следует переопределять только в том случае, когда класс содержит большое число свойств, значения которых взаимосвязаны. • Чтобы улучшить производительность приложения, реакцию приложения на обновление свойств зависимостей, которые не связаны между собой, лучше размещать в методах обратного вызова CoerceValueCallback или PropertyChangedCallback, которые регистрируются для конкретных свойств. • В переопределенной версии виртуального метода OnPropertyChangedнадо вызвать реализацию из базового класса, в противном случае система свойств WPF будет работать неправильно. • В методе OnPropertyChangedне рекомендуется инициировать события, так как это может привести к повторным вызовам метода и к ухудшению производительности приложения.
Свойства зависимостей и конструкторы класса • Не следует устанавливать значения свойства зависимостей в конструкторах классов, так как это может привести к проблемам при инициализации объекта во время выполнения. • Виртуальный метод OnPropertyChanged или методы обратного вызова ValidateValueCallback, PropertyChangedCallback и CoerceValueCallback могут быть вызваны системой свойств WPF во время выполнения SetValue, который устанавливает значение свойства зависимости. • Если вызов этих методов произойдет на незавершенной стадии инициализации экземпляра объекта, некоторые ссылки могуn иметь значение null, и будет брошено исключение.