15_Березина_UserControl

advertisement
Классы Windows Presentation Foundation
System.Object
DispatcherObject
Application
DependencyObject
NavigationService
FrameworkTemplate
Visual
ContentElement
UIElement
FrameworkContentElement
Style
FrameworkElement
Page
Shape
TextBlock
ContentControl
RangeBase
TextBoxBase
Frame
Slider
TextBox
Window
ProgressBar
RichTextBox
Grid
ItemsControl
Menu
Button
Toolbar
TreeViewItem
Selector
RepeatButton
TabControl
ToggleButton
RadioButton
ListBox
ListView
TreeView
UserControl
ContextMenu
HeaderedItemsControl
MenuItem
CheckBox
Canvas
MenuBase
NavigationWindow
ButtonBase
Panel
ToolBarTray
Control
ComboBox
Модели пользовательских элементов управления
 WPF предоставляет три программных модели для создания пользовательских
элементов управления:
• Элементы управления, использующие базовый класс UserControl, представляют
собой контейнеры из существующих элементов управления. Эти элементы не
поддерживает настройку с помощью DataTemplate или ControlTemplate.
• Пользовательские элементы управления на базе класса Control свое визуальное
представление определяют при помощи шаблонов. Это позволяет отделить рабочую
логику от визуального представления элемента.
• Элементы управления, использующие в качестве непосредственного базового
класса FrameworkElement, сами выполняют отрисовку.
Свойства зависимостей пользовательского
элемента управления
 В пользовательском элементе управления можно зарегистрировать собственные
свойства зависимостей, что дает возможность работать с ними так же, как и со свойствами
любого элемента управления, поставляемого с WPF, в частности, можно
• задать значение свойства в стиле;
• выполнить привязку свойства к источнику данных;
• как значение свойства использовать динамический ресурс;
• выполнить анимацию для свойства;
• унаследовать значение свойства от родительского элемента в дереве элементов ( в
этом случае необходима регистрация с помощью метода RegisterAttached);
• получать уведомление от системы свойств WPF об изменении значения свойства.
Регистрация свойства зависимостей
пользовательского элемента управления
 Свойство зависимостей регистрируется с помощью метода Register класса
DependencyProperty. Метод добавляет запись в таблице, которая поддерживается
системой свойств WPF, и предоставляет свойству уникальный идентификатор. Этот
идентификатор сохраняется в поле public static readonly типа DependencyProperty как часть
класса и используется в последующих операциях системы свойств.
 В примере в классе CityComboBox регистрируется свойство CityProperty:
class CityComboBox : ComboBox
{
private static string[] CityList = { "Москва", "Петербург", "Новгород" };
public static readonly DependencyProperty CityProperty;
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);
}
}
 Если выполнены не все соглашения об именах свойства зависимости, это может
привести к проблемам при работе с ним, так как большинство инструментов предполагает
выполнение этих правил именования объектов, связанных со свойством зависимости.
Метаданные свойства зависимости
 При регистрации свойства зависимостей можно
System.Object
System.Windows.PropertyMetadata
System.Windows.UIPropertyMetadata
System.Windows.FrameworkPropertyMetadata
задать некоторые характеристики свойства,
используя объект класса PropertyMetadata (или
производного класса ).
 Часть характеристик можно задать в
конструкторах классов, другие передаются через
свойства объекта PropertyMetadata с доступом { get;
set}. Метаданные нельзя изменить после
регистрации свойства зависимостей.
 Конструкторы для метаданных с максимальным числом параметров
public PropertyMetadata ( Object defaultValue,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback );
public UIPropertyMetadata ( Object defaultValue,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback,
bool isAnimationProhibited );
public FrameworkPropertyMetadata( Object defaultValue,
FrameworkPropertyMetadataOptions flags,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback,
bool isAnimationProhibited,
UpdateSourceTrigger defaultUpdateSourceTrigger );
Некоторые свойства класса FrameworkPropertyMetadata
 Некоторые свойства , например DefaultValue, имеют доступ { get; set; }. Значения этих
свойств можно изменить после их инициализации в конструкторе.
 После регистрации свойства зависимостей с помощью методов Register, AddOwner или
OverrideMetadata объект с метаданными становится неизменяемым.
public Object
DefaultValue { get; set; }
Значение по умолчанию для свойства. Унаследовано от
PropertyMetadata.
public bool
Inherits { get; set; }
True, если значение свойства зависимостей может
наследоваться вложенными элементами. Унаследовано от
PropertyMetadata.
public bool
IsNotDataBindable
{ get; set; }
True, если свойство не может быть задано в выражении
привязки.
public bool
BindsTwoWayByDefault
{ get; set; }
True, если по умолчанию для свойства будет использоваться
двусторонняя привязка.
public PropertyChangedCallback
PropertyChangedCallback
{ get; set; }
Метод обратного вызова при изменении значения свойства.
Унаследовано от PropertyMetadata.
public CoerceValueCallback
CoerceValueCallback
{ get; set; }
Метод обратного вызова при приведении (coerce) значения
свойства. Унаследовано от PropertyMetadata.
Проверка и обратные вызовы свойства
зависимостей
 Проверка корректности значения свойства зависимости выполняется в отдельном
методе, а не в упаковщиках свойства { 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 ( DependencyObject dobj,
Object baseValue );
 Метод CoerceValueCallback получает два параметра – новое значение свойства и
объект, к которому оно применяется. Метод вызывается до изменения значения свойства,
старое значение свойства доступно через объект dobj.
 Так как метод CoerceValueCallback имеет доступ к объекту dobj, для которого
проверяется значение свойства, его удобно использовать при работе со свойствами,
значения которых взаимосвязаны.
 Метод обратного вызова CoerceValueCallback для свойства зависимостей вызывается в
результате явного или неявного вызова метода CoerceValue из класса DependencyObject.
public void CoerceValue ( DependencyProperty dp );
PropertyChangedCallback
 Делегат PropertyChangedCallback определяет тип метода обратного вызова, который
инициируется при изменении действующего значения свойства зависимостей:
public delegate void PropertyChangedCallback( DependencyObject dobj,
DependencyPropertyChangedEventArgs e );
 В классе DependencyPropertyChangedEventArgs, объект которого передается через
второй параметр, определены свойства
public Object NewValue { get; }
public Object OldValue { get; }
public DependencyProperty
Property { get; }
Значение свойства зависимостей после
изменения.
Значение свойства зависимостей до
изменения.
Свойство зависимостей, которое изменило
значение.
 В методе можно инициировать событие изменения значения свойства, если эта
информация полезна другим классам.
Виртуальный метод 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, и будет брошено
исключение.
Download