Freigeben über


Übersicht über angefügte Ereignisse

Extensible Application Markup Language (XAML) definiert eine Sprachkomponente und einen Ereignistyp mit der Bezeichnung angefügtes Ereignis. Das Konzept eines angefügten Ereignisses ermöglicht es, einen Handler für ein bestimmtes Ereignis zu einem beliebigen Element hinzuzufügen, das nicht das Element sein muss, das dieses Ereignis tatsächlich definiert oder erbt. In diesem Fall wird das Ereignis weder durch das Objekt, das das Ereignis potenziell auslöst, noch durch die behandelnde Zielinstanz definiert oder steht in keiner Weise in einem "Besitzverhältnis" dazu.

Dieses Thema enthält folgende Abschnitte.

  • Vorbereitungsmaßnahmen
  • Syntax für angefügte Ereignisse
  • Implementierung von angefügten Ereignissen in WPF
  • Szenarien für angefügte Ereignisse
  • Behandeln eines angefügten Ereignisses in WPF
  • Definieren eigener angefügter Ereignisse als Routingereignisse
  • Auslösen eines angefügten WPF-Ereignisses
  • Verwandte Abschnitte

Vorbereitungsmaßnahmen

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

Syntax für angefügte Ereignisse

Angefügte Ereignisse haben eine XAML-Syntax und ein Codierungsmuster, das der zugrunde liegende Code verwenden muss, damit angefügte Ereignisse unterstützt werden.

In der XAML-Syntax wird das angefügte Ereignis nicht einfach durch seinen Ereignisnamen angegeben, sondern durch seinen besitzenden Typ plus dem Ereignisnamen, getrennt durch einen Punkt (.). Da der Ereignisname durch den Namen des besitzenden Typs qualifiziert wird, ermöglicht die Syntax für angefügte Ereignisse das Anfügen eines angefügten Ereignisse an jedes Element, das instanziiert werden kann.

So ist beispielsweise Folgendes 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 Präfix aqua:. Das Präfix ist in diesem Fall notwendig, da das angefügte Ereignis ein benutzerdefiniertes Ereignis ist, das aus einem benutzerdefinierten zugeordneten xmlns stammt.

Implementierung von angefügten Ereignissen in WPF

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

Szenarien für angefügte Ereignisse

In WPF sind angefügte Ereignisse in bestimmten Featurebereichen vorhanden, in denen eine Abstraktion auf Dienstebene besteht, beispielsweise für durch die statische Mouse-Klasse oder die Validation-Klasse aktivierte Ereignisse. Klassen, die mit dem Dienst interagieren oder den Dienst verwenden, können entweder das Ereignis in der Syntax für angefügte Ereignisse verwenden oder das angefügte Ereignis als Routingereignis festlegen, das Teil der Art und Weise ist, in der die Klasse die Funktionen des Diensts integriert.

In WPF sind zwar eine Reihe angefügter Ereignisse definiert, aber die Szenarien, in denen angefügte Ereignisse direkt verwendet oder behandelt werden, sind sehr begrenzt. Im Allgemeinen wird das angefügte Ereignis zu Architekturzwecken eingesetzt, dann aber an ein nicht angefügtes (durch einen CLR-"Wrapper" für Ereignisse gesichertes) Routingereignis weitergeleitet.

So kann beispielsweise das zugrunde liegende angefügte Ereignis Mouse.MouseDown einfacher auf einem gegebenen UIElement behandelt werden, wenn MouseDown auf diesem UIElement verwendet wird, anstatt die Syntax für angefügte Ereignisse in XAML oder im Code zu verwenden. Das angefügte Ereignis dient einem Architekturzweck, da es eine zukünftige Erweiterung der Eingabegeräte gestattet. Das hypothetische Gerät muss nur Mouse.MouseDown auslösen, um eine Mauseingabe zu simulieren und muss dazu nicht von Mouse abgeleitet werden. Dieses Szenario bedingt jedoch eine Codebehandlung der Ereignisse, und die XAML-Behandlung des angefügten Ereignisses ist für dieses Szenario nicht relevant.

Behandeln eines angefügten Ereignisses in WPF

Die Vorgehensweise zur Behandlung eines angefügten Ereignisses sowie der Handlercode, den Sie schreiben, sind im Prinzip gleich wie bei Routingereignissen.

Im Allgemeinen unterscheidet sich ein angefügtes WPF-Ereignis nur geringfügig von einem WPF-Routingereignis. Die Unterschiede liegen in der Quelle des Ereignisses und wie es durch eine Klasse als Member verfügbar gemacht wird (dies wirkt sich auch auf die XAML-Handlersyntax aus).

Wie oben erwähnt sind jedoch die vorhandenen angefügten WPF-Ereignisse nicht speziell für die Behandlung in WPF bestimmt. Der Zweck des Ereignisses ist meist, einem zusammengesetzten Element die Meldung eines Zustands an ein übergeordnetes Element zu ermöglichen. In diesem Fall wird das Ereignis üblicherweise im Code ausgelöst und beruht auch auf der Klassenbehandlung in der relevanten übergeordneten Klasse. So wird beispielsweise erwartet, dass Elemente innerhalb eines Selector das angefügte Selected-Ereignis auslösen, das dann durch die Selector-Klasse behandelt wird und anschließend durch die Selector-Klasse potenziell in das Routingereignis SelectionChanged umgewandelt wird. Weitere Informationen über Routingereignisse und Klassenbehandlung finden Sie unter Markieren von Routingereignissen als behandelt und Klassenbehandlung.

Definieren eigener angefügter Ereignisse als Routingereignisse

Wenn Sie aus allgemeinen WPF-Basisklassen ableiten, können Sie eigene angefügte Ereignisse durch Einschließen bestimmter Mustermethoden in Ihre Klasse und durch Verwenden von Hilfsmethoden implementieren, die bereits in den Basisklassen vorhanden sind.

Das Muster sieht wie folgt aus:

  • Ein Methode Add*Handler mit zwei Parametern. Der erste Parameter muss das Ereignis identifizieren, und das identifizierte Ereignis muss Namen mit * im Methodennamen entsprechen. Der zweite Parameter ist der hinzuzufügende Handler. Die Methode muss öffentlich und statisch sein und ohne Rückgabewert.

  • Ein Methode Remove*Handler mit zwei Parametern. Der erste Parameter muss das Ereignis identifizieren, und das identifizierte Ereignis muss Namen mit * im Methodennamen entsprechen. Der zweite Parameter ist der zu entfernende Handler. Die Methode muss öffentlich und statisch sein und ohne Rückgabewert.

Die Add*Handler-Accessormethode vereinfacht die XAML-Verarbeitung, wenn angefügte Ereignishandlerattribute für ein Element deklariert sind. Die Add*Handler-Methode und die Remove*Handler-Methode ermöglichen auch den Codezugriff auf den Ereignishandlerspeicher für das angefügte Ereignis.

Dieses allgemeine Muster ist noch nicht genau genug für die praktische Implementierung in einem Framework, da eine gegebene XAML-Readerimplementierung unterschiedliche Schemas für das Identifizieren zugrunde liegender Ereignisse in der unterstützenden Sprache und Architektur hat. Dies ist einer der Gründe, warum WPF angefügte Ereignisse als Routingereignisse implementiert; der Bezeichner, der für ein Ereignis verwendet wird (RoutedEvent), ist bereits durch das WPF-Ereignissystem definiert. Das Weiterleiten eines Ereignisses ist außerdem eine natürliche Implementierungserweiterung im XAML-Sprachebenenkonzept eines angefügten Ereignisses.

Die Add*Handler-Implementierung für ein angefügtes WPF-Ereignis besteht darin, den AddHandler mit dem Routingereignis und dem Handler als Argumente aufzurufen.

Diese Implementierungsstrategie und das Routingereignissystem beschränken im Allgemeinen die Behandlung angefügter Ereignisse auf vom UIElement abgeleitete Klassen oder vom ContentElement abgeleitete Klassen, da nur diese Klassen über AddHandler-Implementierungen verfügen.

Der folgende Code definiert beispielsweise das angefügte NeedsCleaning-Ereignis für die Besitzerklasse Aquarium unter Verwendung der WPF-Strategie für angefügte Ereignisse, bei der das angefügte Ereignis als Routingereignis deklariert wird.

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
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);
    }
}

Beachten Sie, dass die Methode, die zur Festlegung des Bezeichnerfelds für das angefügte Ereignis verwendet wird (RegisterRoutedEvent) tatsächlich die gleiche Methode ist, die zum Registrieren eines nicht angefügten Ereignisses verwendet wird. Angefügte Ereignisse und Routingereignisse werden in einem zentralisierten internen Speicher registriert. Durch diese Implementierung eines Ereignisspeichers wird das Konzept der "Ereignisse als Schnittstelle" aktiviert, das unter Übersicht über Routingereignisse erläutert wird.

Auslösen eines angefügten WPF-Ereignisses

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

Wenn Sie jedoch ein benutzerdefiniertes angefügtes Ereignis auf der Basis des WPF-Modells definieren, bei dem angefügte Ereignisse auf RoutedEvent basieren, können Sie RaiseEvent verwenden, um ein angefügtes Ereignis durch jedes UIElement oder ContentElement auslösen zu lassen. Für das Auslösen eines Routingereignisses (ob 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. Ihr Dienst ist zuständig dafür, das Element zu bestimmen, das als Quelle in der Struktur gemeldet wird.

Siehe auch

Konzepte

Übersicht über Routingereignisse

Ausführliche Erläuterung der XAML-Syntax

XAML- und benutzerdefinierte Klassen für WPF