Übersicht über angefügte Ereignisse (WPF .NET)

Extensible Application Markup Language (XAML) definiert eine Sprachkomponente und einen Ereignistyp, der als angefügtes Ereignis bezeichnet wird. Angefügte Ereignisse können verwendet werden, um ein neues routingfähiges Ereignis in einer Nicht-Elementklasse zu definieren und dieses Ereignis für jedes Element in Ihrer Struktur zu auslösen. Dazu müssen Sie das angefügte Ereignis als routingfähiges Ereignis registrieren und spezifischen Sicherungscode bereitstellen, der angefügte Ereignisfunktionen unterstützt. Da angefügte Ereignisse als routingfähige Ereignisse registriert werden, werden sie beim Auslösen eines Elements durch die Elementstruktur verteilt.

Wichtig

Die Dokumentation zum Desktopleitfaden für .NET 6 und .NET 5 (einschließlich .NET Core 3.1) wird derzeit erstellt.

Voraussetzungen

Im Artikel wird davon ausgegangen, dass sie grundlegende Kenntnisse über Windows Presentation Foundation (WPF)-Routingereignisse haben und dass Sie die Übersicht über Routingereignisse und XAML in WPF gelesen haben. Um den Beispielen in diesem Artikel zu folgen, hilft es Ihnen, wenn Sie mit XAML vertraut sind und wissen, wie Sie WPF-Anwendungen schreiben.

Angefügte Ereignissyntax

In der XAML-Syntax wird ein angefügtes Ereignis durch seinen Ereignisnamen und seinen Besitzertyp in Form von <owner type>.<event name>. Da der Ereignisname mit dem Namen seines Besitzertyps qualifiziert ist, kann das Ereignis an jedes Element angefügt werden, das instanziiert werden kann. Diese Syntax gilt auch für Handler für reguläre Routingereignisse, die an ein beliebiges Element entlang der Ereignisroute angefügt sind.

Die folgende XAML-Attributsyntax fügt den AquariumFilter_Clean Handler für das angefügte Ereignis an das AquariumFilter.Cleanaquarium1 Element an:

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

In diesem Beispiel ist das aqua: Präfix erforderlich, da die AquariumFilter Klassen Aquarium in einem anderen CLR-Namespace (Common Language Runtime) und assembly vorhanden sind.

Sie können auch Handler für angefügte Ereignisse im CodeBehind anfügen. Rufen Sie dazu die AddHandler Methode für das Objekt auf, an das der Handler angefügt werden soll, und übergeben Sie den Ereignisbezeichner und Handler als Parameter an die Methode.

Implementieren angefügter Ereignisse durch WPF

WPF-angefügte Ereignisse werden als Routingereignisse implementiert, die von einem RoutedEvent Feld unterstützt werden. Daher werden angefügte Ereignisse nach dem Auslösen durch die Elementstruktur verteilt. Im Allgemeinen ist das Objekt, das das angefügte Ereignis auslöst, das als Ereignisquelle bezeichnet wird, eine System- oder Dienstquelle. System- oder Dienstquellen sind kein direkter Teil der Elementstruktur. Bei anderen angefügten Ereignissen kann es sich bei der Ereignisquelle um ein Element in der Struktur handeln, z. B. eine Komponente innerhalb eines zusammengesetzten Steuerelements.

Angefügte Ereignisszenarien

In WPF werden angefügte Ereignisse in bestimmten Featurebereichen verwendet, in denen eine Abstraktion auf Dienstebene vorhanden ist. Beispielsweise verwendet WPF angefügte Ereignisse, die von den statischen Mouse oder Validation Klassen aktiviert werden. Klassen, die mit einem Dienst interagieren oder verwenden, können entweder mit einem Ereignis mithilfe der angefügten Ereignissyntax interagieren oder das angefügte Ereignis als routingfähiges Ereignis anzeigen. Letztere Option ist Teil der Integration der Funktionen des Diensts durch eine Klasse.

Das WPF-Eingabesystem verwendet umfangreiche angefügte Ereignisse. Fast alle angefügten Ereignisse werden jedoch als gleichwertige nicht angefügte Routingereignisse über Basiselemente angezeigt. Jedes Routingeingabeereignis ist ein Element der Basiselementklasse und wird mit einem CLR-Ereignis "wrapper" gesichert. Sie werden keine angefügten Ereignisse direkt verwenden oder behandeln. So ist es beispielsweise einfacher, das zugrunde liegende angefügte Mouse.MouseDown Ereignis auf einem durch UIElement das entsprechende UIElement.MouseDown routingfähige Ereignis zu behandeln, als die Verwendung der angefügten Ereignissyntax in XAML oder CodeBehind.

Angefügte Ereignisse dienen einem Architekturzweck, indem eine zukünftige Erweiterung der Eingabegeräte ermöglicht wird. Ein neues Eingabegerät muss beispielsweise nur zum Simulieren der Mauseingabe auslösen Mouse.MouseDown , und es muss nicht von Mouse dieser abgeleitet werden. Dieses Szenario umfasst die Codebehandlung des Ereignisses, da die XAML-Behandlung des angefügten Ereignisses nicht relevant wäre.

Behandeln eines angefügten Ereignisses

Der Prozess zum Codieren und Behandeln eines angefügten Ereignisses ist grundsätzlich identisch mit einem nicht angefügten Routingereignis.

Wie bereits erwähnt, sollen vorhandene angefügte WPF-Ereignisse normalerweise nicht direkt in WPF behandelt werden. Häufiger besteht der Zweck eines angefügten Ereignisses darin, ein Element innerhalb eines zusammengesetzten Steuerelements zu ermöglichen, seinen Zustand an ein übergeordnetes Element innerhalb des Steuerelements zu melden. In diesem Szenario wird das Ereignis im Code ausgelöst und basiert auf der Klassenbehandlung in der relevanten übergeordneten Klasse. Beispielsweise werden Elemente innerhalb eines Selector Ereignisses erwartet, die das Selected angefügte Ereignis auslösen, das dann von der Selector Klasse behandelt wird. Die Selector Klasse konvertiert das Selected Ereignis potenziell in das SelectionChanged routingfähige Ereignis. Weitere Informationen zu Routingereignissen und Klassenbehandlung finden Sie unter Markieren von Routingereignissen als behandelt und Klassenbehandlung.

Definieren eines benutzerdefinierten angefügten Ereignisses

Wenn Sie von gängigen WPF-Basisklassen abgeleitet werden, können Sie Ihr benutzerdefiniertes angefügtes Ereignis implementieren, indem Sie zwei Accessormethoden in Ihrer Klasse einschließen. Diese Methoden sind:

  • Eine Addevent< nameHandler-Methode> mit einem ersten Parameter, der das Element ist, auf dem der Ereignishandler angefügt wird, und einen zweiten Parameter, der dem hinzuzufügenden Ereignishandler ist. Die Methode muss und static, ohne Rückgabewert, seinpublic. Die Methode ruft die AddHandler Basisklassenmethode auf, wobei das Routingereignis und der Handler als Argumente übergeben werden. Diese Methode unterstützt die XAML-Attributsyntax zum Anfügen eines Ereignishandlers an ein Element. Diese Methode ermöglicht auch den Codezugriff auf den Ereignishandlerspeicher für das angefügte Ereignis.

  • Eine Removeevent< nameHandler-Methode> mit einem ersten Parameter, der das Element ist, auf dem der Ereignishandler angefügt ist, und einen zweiten Parameter, der der zu entfernende Ereignishandler ist. Die Methode muss und static, ohne Rückgabewert, seinpublic. Die Methode ruft die RemoveHandler Basisklassenmethode auf, wobei das Routingereignis und der Handler als Argumente übergeben werden. Diese Methode ermöglicht den Codezugriff auf den Ereignishandlerspeicher für das angefügte Ereignis.

WPF implementiert angefügte Ereignisse als routingfähige Ereignisse, da der Bezeichner für ein Ereignis RoutedEvent vom WPF-Ereignissystem definiert wird. Außerdem ist das Routing eines Ereignisses eine natürliche Erweiterung des XAML-Sprachebenenkonzepts eines angefügten Ereignisses. Diese Implementierungsstrategie beschränkt die Behandlung angefügter Ereignisse auf UIElement abgeleitete Klassen oder ContentElement abgeleitete Klassen, da nur diese Klassen Implementierungen aufweisen AddHandler .

Der folgende Code definiert beispielsweise das Clean angefügte Ereignis in der AquariumFilter Besitzerklasse, das keine Elementklasse ist. Der Code definiert das angefügte Ereignis als routingfähiges Ereignis und implementiert die erforderlichen Accessormethoden.

public class AquariumFilter
{
    // Register a custom routed event using the bubble routing strategy.
    public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));

    // Provide an add handler accessor method for the Clean event.
    public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.AddHandler(CleanEvent, handler);
    }

    // Provide a remove handler accessor method for the Clean event.
    public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.RemoveHandler(CleanEvent, handler);
    }
}
Public Class AquariumFilter

    ' Register a custom routed event using the bubble routing strategy.
    Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))

    ' Provide an add handler accessor method for the Clean event.
    Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[AddHandler](CleanEvent, handler)
        End If
    End Sub

    ' Provide a remove handler accessor method for the Clean event.
    Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[RemoveHandler](CleanEvent, handler)
        End If
    End Sub

End Class

Die RegisterRoutedEvent Methode, die den angefügten Ereignisbezeichner zurückgibt, ist die gleiche Methode, mit der nicht angefügte Routingereignisse registriert werden. Sowohl angefügte als auch nicht angefügte Routingereignisse werden in einem zentralen internen Speicher registriert. Diese Ereignisspeicherimplementierung ermöglicht das Konzept "Ereignisse als Schnittstelle", das in der Übersicht über Routed-Ereignisse erläutert wird.

Im Gegensatz zum CLR-Ereignis "Wrapper", der verwendet wird, um nicht angefügte Routingereignisse zu sichern, können die angefügten Ereigniszugriffsmethoden in Klassen implementiert werden, die nicht von UIElement oder ContentElementabgeleitet werden. Dies ist möglich, da der angefügte Ereignisbackcode die UIElement.AddHandler und UIElement.RemoveHandler Methoden für eine übergebene Instanz aufruft UIElement . Im Gegensatz dazu ruft der CLR-Wrapper für nicht angefügte Routingereignisse diese Methoden direkt auf der eigenen Klasse auf, sodass die Klasse von UIElementabgeleitet werden muss.

Auslösen eines angefügten WPF-Ereignisses

Der Prozess zum Auslösen eines angefügten Ereignisses ist im Wesentlichen identisch mit einem nicht angefügten Routingereignis.

In der Regel muss Ihr Code keine vorhandenen WPF-definierten angefügten Ereignisse auslösen, da diese Ereignisse dem allgemeinen konzeptuellen Modell des Diensts folgen. In diesem Modell sind Dienstklassen wie z InputManager. B. für das Auslösen von WPF-definierten angefügten Ereignissen verantwortlich.

Verwenden Sie beim Definieren eines benutzerdefinierten angefügten Ereignisses mithilfe des WPF-Modells angefügter Ereignisse auf Routingereignissen die UIElement.RaiseEvent Methode zum Auslösen eines angefügten Ereignisses auf einem UIElement beliebigen Oder ContentElement. Wenn Sie ein Routingereignis auslösen, unabhängig davon, ob es angefügt ist oder nicht, müssen Sie ein Element in Ihrer Elementstruktur als Ereignisquelle festlegen. Diese Quelle wird dann als RaiseEvent Anrufer gemeldet. Wenn Sie beispielsweise das AquariumFilter.Clean angefügte Routingereignis auslösen möchten, wird folgendes aquarium1ausgeführt:

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

Im vorherigen Beispiel aquarium1 ist die Ereignisquelle.

Siehe auch