Übersicht über angefügte Ereignisse

Extensible Application Markup Language (XAML) definiert eine Sprachkomponente und einen Ereignistyp, der als angefügtes Ereignis bezeichnet wird. Mit dem Konzept eines angefügten Ereignisses können Sie einen Handler für ein bestimmtes Ereignis zu einem beliebigen Element und nicht zu einem Element, das tatsächlich das Ereignis definiert oder erbt, hinzufügen. In diesem Fall definiert oder „besitzt“ weder das Objekt, das potenziell das Ereignis auslöst, noch die Instanz der Richtungsbehandlung das Ereignis.

Voraussetzungen

In diesem Thema wird davon ausgegangen, dass Sie die Artikel Übersicht über Routingereignisse und XAML im WPF gelesen haben.

Syntax der angefügten Ereignisse

Angefügte Ereignisse haben eine XAML-Syntax und ein Codierungsmuster, die von zugrunde liegendem Code verwendet werden müssen, damit die Verwendung angefügter Ereignisse unterstützt wird.

In der XAML-Syntax wird das angefügte Ereignis nicht einfach durch seinen Ereignisnamen, sondern durch seinen besitzenden Typ plus dem Ereignisnamen, getrennt durch einen Punkt (.) angegeben. Da der Name des Ereignisses mit dem Namen des besitzenden Typs qualifiziert wird, ermöglicht es die Syntax der angefügten Ereignisse jedem angefügten Ereignis an jedes Element angefügt zu werden, die instanziiert werden können.

Folgendes ist z. B. die XAML-Syntax für das Anfügen eines Handlers für ein benutzerdefiniertes angefügtes NeedsCleaning-Ereignis:

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

Beachten Sie das aqua:-Präfix. Das Präfix ist in diesem Fall erforderlich, da das angefügte Ereignis ein benutzerdefiniertes Ereignis ist, das aus einer benutzerdefinierten zugeordneten xmlns stammt.

So implementiert WPF angefügte Ereignisse

In WPF werden angefügte Ereignisse durch ein RoutedEvent-Feld gesichert und durch die Baumstruktur weitergeleitet, nachdem sie ausgelöst werden. In der Regel ist die Quelle des angefügten Ereignisses (das Objekt, welches das Ereignis auslöst) eine System- oder Dienstquelle, und das Objekt, das den Ereignis auslösenden Code ausführt, ist daher nicht direkter Teil der Elementstruktur.

Szenarios für angefügte Ereignisse

In WPF sind angefügte Ereignisse in bestimmten Funktionsbereichen vorhanden, in denen Abstraktion auf Dienstebene besteht, z.B. für die Ereignisse, die durch die statischen Klassen Mouse oder Validation aktiviert wurden. Klassen, die mit dem Dienst interagieren oder ihn verwenden, können entweder das Ereignis in der Syntax für angefügte Ereignisse verwenden, oder sie können das angefügte Ereignis als Routingereignis darstellen, das Teil davon ist, wie die Klasse die Funktionen des Diensts integriert.

Obwohl WPF eine Reihe von angefügten Ereignissen definiert, sind die Szenarios sehr begrenzt, in denen Sie das angefügte Ereignis direkt verwenden oder behandeln werden. Im Allgemeinen dient das angefügte Ereignis einem Zweck der Architektur, aber dann wird es an ein nicht angefügtes Routingereignis weitergeleitet (gesichert mit einem CLR-Ereigniswrapper).

Zum Beispiel kann das zugrundeliegende angehängte Mouse.MouseDown-Ereignis einfacher durch ein UIElement unter Verwendung von MouseDown bei diesem UIElement gehandhabt werden, anstatt sich mit der Syntax für angehängte Ereignisse entweder in XAML oder im Code zu beschäftigen. Das angefügte Ereignis dient einem Zweck in der Architektur, da es die zukünftige Erweiterung der Eingabegeräte ermöglicht. Das hypothetische Gerät müsste nur Mouse.MouseDown auslösen, um die Mauseingabe zu simulieren, und bräuchte dazu nicht von Mouse abzuleiten. Dieses Szenario beinhaltet jedoch Code zur Verarbeitung von Ereignissen, und die XAML-Behandlung des angefügten Ereignisses ist nicht für dieses Szenario relevant.

Behandeln eines angefügten Ereignisses in WPF

Der Prozess für die Behandlung eines angefügten Ereignisses und den von Ihnen geschriebenen Handlercode ist im Grunde derselbe wie für ein Routingereignis.

Im Allgemeinen unterscheidet sich ein angefügtes WPF-Ereignis nicht sehr von einem WPF-Routingereignis. Die Unterschiede bestehen in der Quelle des Ereignisses und wie es durch eine Klasse als Member verfügbar gemacht wird (was auch die XAML-Handlersyntax beeinflusst).

Aber wie oben erwähnt sind die vorhandenen angefügten WPF-Ereignisse nicht speziell für die Behandlung in WPF bestimmt. Der Zweck des Ereignisses ist häufiger das Aktivieren eines zusammengesetzten Elements, um den Status an ein übergeordnetes Element in Zusammensetzung zu melden. In diesem Fall wird das Ereignis in der Regel im Code ausgelöst und beruht auf Klassenbehandlung in der entsprechenden übergeordneten Klasse. So wird beispielsweise erwartet, dass Elemente innerhalb eines Selector das angehängte Selected-Ereignis auslösen, das dann von der Klasse Selector behandelt und dann möglicherweise von der Klasse Selector in ein anderes Routingereignis, SelectionChanged, umgewandelt wird. Weitere Informationen über Routingereignisse und Klassenbehandlung finden Sie unter Markieren von Routingereignissen als behandelt und Klassenbehandlung.

Definieren Ihres eigenen angefügten Ereignisses als Routingereignisse

Wenn Sie von allgemeinen WPF-Basisklassen ableiten, können Sie eigene angefügte Ereignisse implementieren, indem Sie bestimmte Mustermethoden in Ihrer Klasse einschließen und Hilfsmethoden verwenden, die bereits in den Basisklassen vorhanden sind.

Das Muster ist wie folgt:

  • Eine Methode AddEventNameHandler mit zwei Parametern. Der erste Parameter ist die Instanz, der der Ereignishandler hinzugefügt wird. Der zweite Parameter ist der hinzuzufügende Handler. Die Methode muss public und static sein, ohne Rückgabewert.

  • Eine Methode RemoveEventNameHandler mit zwei Parametern. Der erste Parameter ist die Instanz, von der der Ereignishandler entfernt wird. Der zweite Parameter ist der entfernende Handler. Die Methode muss public und static sein, ohne Rückgabewert.

Die Zugriffsmethode AddEventNameHandler vereinfacht die XAML-Verarbeitung, wenn Attribute von angefügten Ereignishandlern für ein Element deklariert sind. Die Methoden AddEventNameHandler und RemoveEventNameHandler ermöglichen auch den Codezugriff auf den Ereignishandlerspeicher für das angefügte Ereignis.

Dieses allgemeine Muster ist noch nicht präzise genug für die praktische Implementierung in einem Framework, da jede gegebene Implementierung des XAML-Readers möglicherweise verschiedene Schemas zum Identifizieren der zugrunde liegenden Ereignisse in der unterstützenden Sprache und Architektur aufweisen könnte. Dies ist einer der Gründe, dass WPF angefügte Ereignisse als Routingereignisse implementiert. Der für ein Ereignis verwendete Bezeichner (RoutedEvent) wurde bereits durch das WPF-Ereignissystem definiert. Darüber hinaus ist das Weiterleiten eines Ereignisses eine natürliche Implementierungserweiterung auf dem WPF-Konzept auf Sprachebene der angefügten Ereignisse.

Die Implementierung AddEventNameHandler für ein angefügtes WPF-Ereignis besteht aus dem Aufruf von AddHandler mit dem Routingereignis und dem Handler als Argumente.

Diese Implementierungsstrategie und das Routingereignissystem beschränken die Behandlung für angefügte Ereignisse entweder auf abgeleitete Klassen des UIElement oder des ContentElement, da nur die Klassen über Implementierungen von AddHandler verfügen.

Der folgende Code definiert z. B. das angefügte NeedsCleaning-Ereignis in der Besitzerklasse Aquarium, unter Verwendung der Strategie des angefügten Ereignisses von WPF für das Deklarieren des angefügten Ereignisses als Routingereignis.

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

Beachten Sie, dass die Methode zum Einrichten des Bezeichnerfelds des angefügten Ereignisses, RegisterRoutedEvent, tatsächlich die gleiche Methode ist, die verwendet wird, um ein nicht angefügtes Ereignis zu registrieren. Angefügte Ereignisse und Routingereignisse werden alle in einem zentralisierten internen Speicher registriert. Diese Implementierung des Ereignisspeichers ermöglicht die konzeptionelle Besonderheit „Ereignisse als Schnittstelle“, die im Artikel Übersicht über Routingereignisse diskutiert wird.

Auslösen eines angefügten Ereignisses von WPF

Sie müssen normalerweise keine vorhandenen, durch WPF definierten angefügten Ereignisse aus Ihrem Code auslösen. Diese Ereignisse folgen dem allgemeinen „Dienst“-Konzeptmodell, und Dienstklassen wie InputManager sind verantwortlich für das Auslösen der Ereignisse.

Wenn Sie jedoch ein benutzerdefiniertes angehängtes Ereignis definieren, das auf dem WPF-Modell der Basis von angehängten Ereignissen auf RoutedEvent basiert, können Sie RaiseEvent verwenden, um ein angehängtes Ereignis von jedem UIElement oder ContentElement auszulösen. Durch das Auslösen eines Routingereignisses (angefügt oder nicht) ist es erforderlich, dass Sie ein bestimmtes Element in der Elementstruktur als Ereignisquelle deklarieren. Diese Quelle wird als RaiseEvent-Aufrufer gemeldet. Das Element zu bestimmen, welches als die Quelle in der Struktur gemeldet ist, unterliegt Ihrer Verantwortung des Dienstes.

Siehe auch