Классы Windows Presentation Foundation - 1 System.Object DispatcherOject Application DependencyObject Visual ContentElement UIElement FrameworkContentElement System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ItemsControl System.Windows.Controls.Primitives.Selector System.Windows.Controls.ComboBox System.Windows.Controls.ListBox System.Windows.Controls.TabControl FrameworkElement Control ItemsControl ContentControl Window ButtonBase Button CheckBox Selector ToggleButton RadioButton ListBox ListView ComboBox TreeView TabControl MenuBase Menu HeaderedItemsControl ContextMenu ToolBar Маршрутизация событий Механизм обработки событий WPF базируется на событиях .NET. Новая концепция - маршрутизация событий ( event routing) – события могут подниматься или спускаться по дереву элементов и вызывать обработчики нескольких слушателей (listeners). Три вида событий: Direct events (прямые события) Возникают в одном элементе и не передаются в другие. Пример – MouseEnter. Bubbling events (поднимающиеся, пузырьковые события ) Начинаются во внутреннем элементе и распространяются во внешние – от дочернего элемента к родительским. Пример – MouseDown. Tunneling events ( туннельные, туннелированные события ) Возникают во внешнем элементе и туннелируются во вложенные элементы – от родительского к дочернему элементу. Пример (PreviewMouseMove). Все туннелируемые события в WPF API имеют префикс “Preview” и обычно имеют соответствующие поднимающиеся события. С точки зрения реализации маршрутизируемое событие - это событие, которое связано с экземпляром класса RoutedEvent, и обрабатывается системой управления событиями WPF (WPF event system). Класс RoutedEvent В классе определены четыре свойства и один метод. Все свойства доступны только для чтения, свои значения они получают при регистрации события с помощью метода RegisterRoutedEvent класса EventManager. Свойства не могут иметь значение null. public Type HandlerType { get; } Тип делегата-обработчика события. public string Name { get; } Имя маршрутизируемого события должно быть уникальным внутри каждого типа-владельца, глобальной уникальности имени не требуется. public Type OwnerType { get; } Тип – владелец события. Если событие имеет дополнительных владельцев (owners added), свойство возвращает первого объявленного владельца. public RoutingStrategy RoutingStrategy { get; } Значение перечисления System.Windows.RoutingStrategy, которое определяет стратегию маршрутизации события (routing strategy), – Tunnel, Bubble или Direct. public RoutedEvent AddOwner ( Type ownerType ); Добавляет новый класс к владельцам события. Возвращаемое значение используется при определении статического поля, представляющее маршрутизируемое событие в новом классевладельце. Класс EventManager Статический класс EventManager регистрирует маршрутизируемые события (routed event) и добавляет обработчики класса ( class handlers) – обработчик, который вызывается до вызова обработчиков, связанных с отдельными экземплярами(объектами) класса. В классе всего 4 статических метода. public static RoutedEvent RegisterRoutedEvent ( string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType ); Регистрирует новое маршрутизируемое событие в системе событий WPF. public static void RegisterClassHandler ( Type classType, RoutedEvent routedEvent, Delegate handler, bool handledEventsToo ); Регистрирует обработчик класса для события с опцией handledEventsToo обработки для событий, которые уже отмечены как обработанные. Перегружен. public static RoutedEvent[] GetRoutedEventsForOwner ( Type ownerType ); Возвращает массив маршрутизируемых событий для типа-владельца ownerType ( включая базовые классы) или null, если тип не имеет маршрутизируемых событий. public static RoutedEvent[] GetRoutedEvents(); Возвращает массив маршрутизируемых событий, зарегистрированных в системе событий WPF в текущий момент. Коллекция содержит все события из WPF API. В процессе работы приложения коллекция может измениться. Метод RegisterRoutedEvent класса EventManager public static RoutedEvent RegisterRoutedEvent ( string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType ); Метод RegisterRoutedEvent регистрирует новое маршрутизируемое событие в системе управления событиями WPF. Параметры метода RegisterRoutedEvent string name Имя регистрируемого события. Имя должно быть уникальным в типе-владельце и не может быть пустой строкой или иметь значение null. RoutingStrategy routingStrategy Значение перечисления System.Windows.RoutingStrategy, которое определяет стратегию маршрутизации события (routing strategy). Значения перечисления – Tunnel, Bubble, Direct. Type handlerType Тип делегата-обработчика. Это должен быть тип-делегат, значение null не допускается. Type ownerType Тип класса-владельца. Не может иметь значение null. Return value – объект типа RoutedEvent Объект типа RoutedEvent , который можно использовать как статическое поле класса и как параметр методов при определении обработчиков событий (подписке на событие). Пример регистрации маршрутизируемого события Маршрутизируемое событие (routed event) • определяется как статическое поле, доступное только для чтения; • регистрируется в статическом конструкторе; • упаковывается как обычное событие .NET. Событие инициируется при вызове метода RaiseEvent из любого класса, производного от FrameworkUIElement. public class MyButtonSimple : Button { public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent ( "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple)); public event RoutedEventHandler Tap { add { AddHandler(TapEvent, value); } remove { RemoveHandler(TapEvent, value); } void RaiseTapEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent); RaiseEvent ( newEventArgs); } protected override void OnClick() { RaiseTapEvent(); } } Класс RoutedEventArgs EventArgs RoutedEventArgs InputEventArgs MouseEventArgs KeyboardEventArgs KeyboardFocusChangedEventArgs KeyEventArgs MouseButtonEventArgs MouseWheelEventArgs QueryCursorEventArgs Конструкторы класса RoutedEventArgs: public RoutedEventArgs(); public RoutedEventArgs ( RoutedEvent routedEvent ); public RoutedEventArgs ( RoutedEvent routedEvent, Object source ); При использовании конструктора без параметров свойства получают значения по умолчанию: null для RoutedEvent, Source и OriginalSource и false для Handled. При вызове метода RaiseEvent() свойствам Source и OriginalSource будут присвоены ссылки на объект, который вызвал( raised) событие, эти значения доступны слушателям в процессе маршрутизации события. Свойства класса RoutedEventArgs Свойства класса RoutedEventArgs доступны в обработчиках маршрутизируемых событий. public RoutedEvent RoutedEvent { get; set; } Значение RoutedEvent, связанное с экземпляром RoutedEventArgs. Значение нельзя изменить в процессе обработки события - будет брошено исключение InvalidOperationException. Значение свойства не может иметь значение null. public Object Source { get; set; } Ссылка на объект, который является источником события. При изменении значения свойства Source свойство OriginalSource сохраняет ссылку на объект, который вызвал метод RaiseEvent. public bool Handled { get; set; } Состояние события. Значение по умолчанию равно false. Значение true указывает, что событие уже было обработано в процессе маршрутизации. Когда свойство получает значение true, событие продолжает движение по маршруту обработки, но будут вызваны только те обработчики, у которых значение свойства HandledEventsToo равно true. public Object OriginalSource { get; } Первоначальный источник события, установленный до любого возможного изменения в процессе обработки. Обработчик класса для маршрутизируемых событий Для маршрутизируемых событий можно определить обработчик класса – статический обработчик, общий для всех экземпляров класса. Обработчики класса вызываются до экземплярных обработчиков. Обработчик класса может установить для события состояние обработанного – присвоить значение true свойству Handled. В этом случае экземплярные объекты вызываться не будут, за исключением тех, которые были зарегистрированы со значением true параметра handledEventsToo. Многие базовые элементы WPF имеют виртуальные обработчики класса. Это дает возможность определить свои версии обработчиков класса без использования вызова метода RegisterClassHandler из статического конструктора класса. В WPF API эти методы определены для событий ввода, их имена начинаются с "On" и включают имя события, например, . События времени существования объекта Все объекты классов, производных от FrameworkElement или FrameworkContentElement, имеют три события времени жизни. Initialized Событие времени работы конструктора. При обработке этого события установлены значения свойств объекта, за исключением динамических ресурсов и привязки данных. Событие возникает последовательно по направлению от дочернего к родительским элементам. При обработке события следует иметь ввиду, что родительские объекты могут быть еще не инициализированы и ссылки имеют нулевые значения. Loaded Возникает после события Initialized, непосредственно перед экранизацией (rendering). При этом уже создано логическое дерево элементов и вычислены все размеры и местоположение элементов. Событие возникает сначала в корневом элементе. Каждый элемент имеет возможность обработать это событие, значение свойства Handled не влияет на обработку. Unloaded Возникает последним. При обработке события следует иметь ввиду, что родительские объекты могут быть уже выгружены, и ссылки на объекты привязки, ресурсы и стили могут быть недействительны. Элементы-контейнеры Класс Window в WPF является производным от класса ContentControl, разрешающего разместить в окне только один дочерний элемент. Чтобы разместить в окне несколько дочерних элементов управления, их необходимо поместить в один из контейнеров, которые могут быть вложены друг в друга. Классы-контейнеры элементов управления являются производными от класса Panel. public abstract class Panel : FrameworkElement, IAddChild {…} public interface IAddChild { void AddChild( Object value ); void AddText( string text ); } public UIElementCollection Children { get; }