Общие сведения о вложенных событиях

XAML (XAML) определяет компонент языка и тип события, называемого вложенным событием. Концепция присоединенного события позволяет добавить обработчик для конкретного события в произвольный элемент, а не в элемент, который фактически определяет или наследует событие. В этом случае ни объект, потенциально вызывающий событие, ни конечный обрабатывающий экземпляр не определяет или иным образом не "владеет" событием.

Предварительные требования

Предполагается, что вы ознакомились с разделами Общие сведения о перенаправленных событиях и Обзор XAML (WPF).

Синтаксис присоединенных событий

Вложенные события имеют синтаксис XAML и шаблон кодирования, который должен использоваться резервным кодом для поддержки использования вложенного события.

В синтаксисе XAML вложенное событие указывается не только именем события, но и типом его владельца и именем события, разделенными точкой (.). Так как имя события квалифицируется с помощью имени типа, которому оно принадлежит, синтаксис присоединенных событий позволяет подключить любое присоединенное событие к любому элементу, для которого может быть создан экземпляр.

Например, ниже приведен синтаксис XAML для присоединения обработчика для пользовательского NeedsCleaning присоединенного события:

<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>

Обратите внимание на префикс aqua:. Префикс необходим в этом случае, поскольку присоединенное событие является пользовательским событием, которое поступает из пользовательского сопоставленного xmlns.

Реализация присоединенных событий в WPF

В WPF вложенные события поддерживаются RoutedEvent полем и направляются через дерево после их возникновения. Как правило, источником присоединенного события (объектом, вызывающим событие) является система или служба, и таким образом, объект, который выполняет код, порождающий это событие, не является непосредственной частью дерева элементов.

Сценарии для присоединенных событий

В WPF вложенные события присутствуют в определенных функциональных областях, где существует абстракция уровня службы, например для событий, включенных статическим Mouse классом или Validation классом. Классы, которые взаимодействуют со службой или используют ее, могут использовать событие в синтаксисе присоединенных событий или предоставить присоединенное событие как перенаправленное событие, которое является частью процесса интеграции возможностей службы классом.

Хотя WPF определяет ряд вложенных событий, сценарии, в которых вы будете использовать или напрямую управлять присоединенным событием, очень ограничены. Как правило, присоединенное событие служит целью архитектуры, но затем перенаправляется в неприсоединенное (с помощью оболочки события CLR) перенаправленное событие.

Например, базовое присоединенное событие Mouse.MouseDown может быть проще обработано в любой заданном с UIElement помощью MouseDown , вместо того чтобы обрабатываться UIElement с синтаксисом вложенных событий в XAML или коде. Присоединенное событие выполняет определенную роль в архитектуре, поскольку оно обеспечивает будущее расширение типов устройств ввода. Гипотетическому устройству пришлось бы вызывать только Mouse.MouseDown для имитации ввода с помощью мыши, а не для Mouse этого. Однако этот сценарий включает обработку кода событий, и обработка XAML присоединенного события не относится к этому сценарию.

Обработка присоединенного события в WPF

Процесс для обработки присоединенного события и код обработчика, который вы будете писать, по сути аналогичны перенаправленному событию.

Как правило, вложенное событие WPF не сильно отличается от перенаправленного события WPF. Различия в том, как источник события и как он предоставляется классом в качестве члена (который также влияет на синтаксис обработчика XAML).

Однако, как отмечалось ранее, существующие подключенные события WPF не предназначены специально для обработки в WPF. Гораздо чаще целью событий является включение составного элемента для передачи состояния в родительский элемент при компоновке. В этом случае событие обычно вызывается в коде и зависит от обработки класса в соответствующем родительском классе. Например, элементы внутри a должны Selector вызывать вложенное Selected событие, которое затем обрабатывается Selector классом и может быть преобразовано Selector классом в другое перенаправленное событие SelectionChanged . Дополнительные сведения о перенаправленных событиях и обработке классов см. в разделе Маркировка перенаправленных событий как обработанных и обработка классов.

Определение собственных присоединенных событий как перенаправленных событий

Если вы наследуете от общих базовых классов WPF, вы можете реализовать собственные вложенные события, включив определенные методы шаблона в класс и используя служебные методы, которые уже имеются в базовых классах.

Шаблон выглядит следующим образом.

  • Метод добавляет обработчик EventName с двумя параметрами. Первый параметр — это экземпляр, в который добавляется обработчик событий. Второй параметр — это добавляемый обработчик событий. Метод должен иметь public значение и static , без возвращаемого значения.

  • Метод удаляет обработчик EventName с двумя параметрами. Первый параметр — это экземпляр, из которого удаляется обработчик событий. Второй параметр — это обработчик событий, который необходимо удалить. Метод должен иметь public значение и static , без возвращаемого значения.

Метод доступа Add ИмяСобытия Handler упрощает обработку XAML при объявлении атрибутов обработчика вложенных событий в элементе. Методы обработчика Add EventName и Remove EventName также обеспечивают доступ кода к хранилищу обработчиков событий для присоединенного события.

Этот общий шаблон еще не достаточен для практической реализации в платформе, так как любая заданная реализация средства чтения XAML может иметь различные схемы для идентификации базовых событий в поддерживающем языке и архитектуре. Это одна из причин, по которой в WPF реализуются вложенные события как перенаправляемые события; Идентификатор, используемый для события ( RoutedEvent ), уже определен системой событий WPF. Кроме того, маршрутизация события является естественным расширением реализации в концепции уровня языка XAML присоединенного события.

Реализация обработчика "Add EventName " для присоединенного события WPF состоит из вызова метода AddHandler с перенаправленным событием и обработчиком в качестве аргументов.

Эта стратегия реализации и система перенаправленных событий в целом ограничивают обработку присоединенных событий UIElement производными классами или ContentElement производными классами, так как только эти классы имеют AddHandler реализации.

Например, следующий код определяет NeedsCleaning присоединенное событие для класса Owner Aquarium , используя стратегию вложенных событий WPF объявления присоединенного события в виде перенаправленного события.

public static readonly RoutedEvent NeedsCleaningEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
Public Shared ReadOnly NeedsCleaningEvent As RoutedEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
Public Shared Sub AddNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
Public Shared Sub RemoveNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub

Обратите внимание, что метод, используемый для установления поля идентификатора присоединенного события, RegisterRoutedEvent фактически является тем же методом, который используется для регистрации неприсоединенного перенаправленного события. Все присоединенные события и перенаправленные события регистрируются в централизованном внутреннем хранилище. Эта реализация хранилища событий обеспечивает поддержку режима "события в качестве интерфейса", который рассматривается в разделе Общие сведения о перенаправленных событиях.

Вызов присоединенного события WPF

Обычно не требуется вызывать существующие присоединенные события, определенные в WPF, из кода. Эти события следуют общей концептуальной модели службы, а классы служб, такие как InputManager , отвечают за создание событий.

Однако при определении пользовательского присоединенного события, основанного на модели WPF для создания присоединенных событий на основе RoutedEvent , можно использовать RaiseEvent для вызова вложенного события из любого UIElement или ContentElement . Для вызова перенаправленного события (присоединенного или нет) требуется объявить конкретный элемент в дереве элементов в качестве источника события. Этот источник сообщается в качестве RaiseEvent вызывающего. За определение того, какой элемент передается как источник в дереве, отвечает служба.

См. также раздел