Freigeben über


Übersicht über Routingereignisse

Entwickler und Komponentenautoren von Windows Presentation Foundation (WPF) können Routingereignisse verwenden, um Ereignisse über eine Elementstruktur zu verteilen und Ereignishandler für mehrere Listener in der Struktur aufzurufen. Diese Features werden in Common Language Runtime (CLR)-Ereignissen nicht gefunden. Mehrere WPF-Ereignisse sind routende Ereignisse, wie z. B. ButtonBase.Click. In diesem Artikel werden grundlegende Routingereigniskonzepte erläutert und Anleitungen zum Zeitpunkt und zur Reaktion auf Routingereignisse angeboten.

Voraussetzungen

In diesem Artikel wird ein Grundwissen über die Common Language Runtime (CLR), objektorientierte Programmierung und darüber, wie das WPF-Elementlayout als Baum konzeptioniert werden kann, vorausgesetzt. Um den Beispielen in diesem Artikel zu folgen, hilft es Ihnen, wenn Sie mit Extensible Application Markup Language (XAML) vertraut sind und wissen, wie WPF-Anwendungen geschrieben werden.

Was ist ein Routingereignis?

Sie können Routingereignisse aus funktionaler oder Implementierungsperspektive in Betracht ziehen:

  • Aus funktionaler Sicht ist ein geroutetes Ereignis ein Ereignistyp, der Handler für mehrere Listener in einem Elementbaum und nicht nur in der Ereignisquelle aufrufen kann. Ein Ereignislistener ist das Element, an das ein Ereignishandler angefügt und aufgerufen wird. Eine Ereignisquelle ist das Element oder Objekt, das ursprünglich ein Ereignis ausgelöst hat.

  • Aus Implementierungsperspektive ist ein routingfähiges Ereignis ein Ereignis, das beim WPF-Ereignissystem registriert ist, von einer Instanz der RoutedEvent Klasse unterstützt und vom WPF-Ereignissystem verarbeitet wird. In der Regel wird ein Routingereignis mit einem CLR-Ereignis-Wrapper implementiert, um das Anfügen von Handlern in XAML und im Code-Behind, wie bei einem CLR-Ereignis, zu ermöglichen.

WPF-Anwendungen enthalten in der Regel viele Elemente, die entweder in XAML deklariert oder im Code instanziiert wurden. Die Elemente einer Anwendung sind in der Elementstruktur vorhanden. Je nachdem, wie ein Routingereignis definiert wird, wenn das Ereignis an einem Quellelement ausgelöst wird, tritt Folgendes auf:

  • Ergibt sich aus dem Quellelement und steigt durch den Elementbaum bis zum Wurzelelement auf, bei dem es sich in der Regel um eine Seite oder ein Fenster handelt.
  • Tunnelt durch die Elementstruktur vom Stammelement zum Quellelement.
  • Wandert nicht durch den Elementbaum und tritt nur beim Quellelement auf.

Betrachten Sie die folgende Teilelementstruktur:

<Border Height="30" Width="200" BorderBrush="Gray" BorderThickness="1">
    <StackPanel Background="LightBlue" Orientation="Horizontal" Button.Click="YesNoCancelButton_Click">
        <Button Name="YesButton">Yes</Button>
        <Button Name="NoButton">No</Button>
        <Button Name="CancelButton">Cancel</Button>
    </StackPanel>
</Border>

Der Elementbaum wird wie gezeigt angezeigt.

Eine XAML-Elementstruktur mit drei Schaltflächen: Ja, Nein und Abbrechen.

Jede der drei Schaltflächen ist eine potenzielle Click Ereignisquelle. Wenn eine der Schaltflächen angeklickt wird, löst sie das Click Ereignis aus, das von der Schaltfläche bis zum Wurzelselement hochwandert. Die Elemente Button und Border verfügen nicht über angefügte Ereignishandler, aber das StackPanel tut es. Möglicherweise haben auch andere Elemente weiter oben in der Struktur, die nicht angezeigt werden, Click Ereignishandler. Wenn das Click Ereignis das StackPanel Element erreicht, ruft das WPF-Ereignissystem den YesNoCancelButton_Click Handler auf, der an das Ereignis angefügt ist. Die Ereignisroute für das Click Ereignis im Beispiel lautet: Button ->StackPanel ->Border -> aufeinander folgende übergeordnete Elemente.

Hinweis

Das Element, das ursprünglich ein Routingereignis ausgelöst hat, wird als die RoutedEventArgs.Source in den Ereignishandlerparametern identifiziert. Der Ereignislistener ist das Element, an das der Ereignishandler angefügt und aufgerufen wird und als Absender in den Ereignishandlerparametern identifiziert wird.

Hochrangige Szenarien für geroutete Ereignisse

Hier sind einige szenarien, die das Routingereigniskonzept motivierten und von einem typischen CLR-Ereignis unterscheiden:

  • Steuerelementkomposition und Kapselung: Verschiedene Steuerelemente in WPF verfügen über ein umfangreiches Inhaltsmodell. Sie können z. B. ein Bild in einem Button platzieren, was den visuellen Baum der Schaltfläche effektiv vergrößert. Das hinzugefügte Bild darf das Treffertestverhalten der Schaltfläche jedoch nicht unterbrechen, was reagieren muss, wenn ein Benutzer auf die Bildpixel klickt.

  • Einzelne Handler-Zuweisungspunkte: Sie können einen Handler für das Ereignis einer jeden Schaltfläche Click registrieren, aber mit gerouteten Ereignissen können Sie einen einzelnen Handler anfügen, wie im vorherigen XAML-Beispiel gezeigt. Auf diese Weise können Sie die Elementstruktur unter dem Singularhandler ändern, z. B. das Hinzufügen oder Entfernen weiterer Schaltflächen, ohne das Ereignis jeder Schaltfläche Click registrieren zu müssen. Wenn das Click Ereignis ausgelöst wird, kann die Handlerlogik bestimmen, wo das Ereignis stammt. Der folgende Handler, der in der zuvor gezeigten XAML-Elementstruktur angegeben ist, enthält diese Logik:

    private void YesNoCancelButton_Click(object sender, RoutedEventArgs e)
    {
        FrameworkElement sourceFrameworkElement = e.Source as FrameworkElement;
        switch (sourceFrameworkElement.Name)
        {
            case "YesButton":
                // YesButton logic.
                break;
            case "NoButton":
                // NoButton logic.
                break;
            case "CancelButton":
                // CancelButton logic.
                break;
        }
        e.Handled = true;
    }
    
    Private Sub YesNoCancelButton_Click(sender As Object, e As RoutedEventArgs)
        Dim frameworkElementSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
    
        Select Case frameworkElementSource.Name
            Case "YesButton"
                ' YesButton logic.
            Case "NoButton"
                ' NoButton logic.
            Case "CancelButton"
                ' CancelButton logic.
        End Select
    
        e.Handled = True
    End Sub
    
  • Klassenbehandlung: Routingereignisse unterstützen einen Klassenereignishandler , den Sie in einer Klasse definieren. Klassenhandler behandeln ein Ereignis, bevor Instanzhandler für dasselbe Ereignis in jeder Instanz der Klasse ausgeführt werden.

  • Verweisen auf ein Ereignis ohne Spiegelung: Jedes Routingereignis erstellt einen RoutedEvent Feldbezeichner, um eine robuste Ereignisidentifikationstechnik bereitzustellen, die keine statische oder Laufzeitreflexion erfordert, um das Ereignis zu identifizieren.

Wie Routingereignisse implementiert werden

Ein Routingereignis ist ein Ereignis, das beim WPF-Ereignissystem registriert ist, unterstützt von einer Instanz der RoutedEvent Klasse und vom WPF-Ereignissystem verarbeitet. Die RoutedEvent instanz, die aus der Registrierung abgerufen wird, wird in der Regel als public static readonly Mitglied der Klasse gespeichert, die sie registriert hat. Diese Klasse wird als "Eigentümer"-Ereignisklasse bezeichnet. In der Regel implementiert ein weitergeleitetes Ereignis einen identisch benannten CLR-Ereignis-Wrapper. Der CLR Ereigniswrapper enthält add- und remove-Accessoren, um das Anfügen von Handlern in XAML und im Code-Behind über sprachspezifische Ereignissyntax zu ermöglichen. Die add und remove Accessoren überschreiben ihre CLR-Implementierung und rufen die Routed-Event-Methoden AddHandler und RemoveHandler auf. Der Routingereignissicherungs- und Verbindungsmechanismus ähnelt konzeptuell der Funktionsweise einer Abhängigkeitseigenschaft einer CLR-Eigenschaft, die von der DependencyProperty Klasse gesichert und beim WPF-Eigenschaftensystem registriert wird.

Im folgenden Beispiel wird das Tap Routingereignis registriert, die zurückgegebene RoutedEvent Instanz gespeichert und ein CLR-Ereigniswrapper implementiert.

// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    name: "Tap",
    routingStrategy: RoutingStrategy.Bubble,
    handlerType: typeof(RoutedEventHandler),
    ownerType: typeof(CustomButton));

// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{
    add { AddHandler(TapEvent, value); }
    remove { RemoveHandler(TapEvent, value); }
}
' Register a custom routed event using the Bubble routing strategy.
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
    name:="Tap",
    routingStrategy:=RoutingStrategy.Bubble,
    handlerType:=GetType(RoutedEventHandler),
    ownerType:=GetType(CustomButton))

' Provide CLR accessors for adding and removing an event handler.
Public Custom Event Tap As RoutedEventHandler
    AddHandler(value As RoutedEventHandler)
        [AddHandler](TapEvent, value)
    End AddHandler

    RemoveHandler(value As RoutedEventHandler)
        [RemoveHandler](TapEvent, value)
    End RemoveHandler

    RaiseEvent(sender As Object, e As RoutedEventArgs)
        [RaiseEvent](e)
    End RaiseEvent
End Event

Routingstrategien

Routingereignisse verwenden eine von drei Routingstrategien:

  • Bubbling: Anfangs werden Ereignishandler für die Ereignisquelle aufgerufen. Das routingfähige Ereignis leitet dann zu aufeinander folgenden übergeordneten Elementen weiter, wobei wiederum die Ereignishandler abgerufen werden, bis es den Stamm der Elementstruktur erreicht. Die meisten Routingereignisse verwenden die Bubbling-Routingstrategie. Ereignisse mit Bubbling-Route werden in der Regel verwendet, um Eingabe- oder Zustandsänderungen aus zusammengesetzten Steuerelementen oder anderen Benutzeroberflächenelementen zu melden.

  • Tunneling: Anfangs werden Ereignishandler an der Wurzel des Elementbaums aufgerufen. Das weitergeleitete Ereignis wird dann zu aufeinanderfolgenden untergeordneten Elementen weitergeleitet und ruft deren Ereignishandler nacheinander auf, bis es die Ereignisquelle erreicht. Ereignisse, die einer Tunnelroute folgen, werden auch als Vorschauereignisse bezeichnet. WPF-Eingabeereignisse werden in der Regel als Vorschau- und Bubblingpaare implementiert.

  • Direct: Es werden nur Ereignishandler für die Ereignisquelle aufgerufen. Diese Nicht-Routing-Strategie entspricht Windows Forms UI-Frameworkereignissen, die standard CLR-Ereignisse sind. Im Gegensatz zu CLR-Ereignissen unterstützen direkte Routingereignisse die Klassenbehandlung und können von EventSetters und EventTriggers verwendet werden.

Gründe für die Verwendung von Routingereignissen

Als Anwendungsentwickler müssen Sie nicht immer wissen oder darauf achten, dass das behandelte Ereignis als Routingereignis implementiert wird. Routingereignisse weisen ein spezielles Verhalten auf, aber dieses Verhalten ist weitgehend unsichtbar, wenn Sie ein Ereignis für das Element behandeln, das es ausgelöst hat. Routingereignisse sind jedoch relevant, wenn Sie einen Ereignishandler an ein übergeordnetes Element anfügen möchten, um Ereignisse zu behandeln, die von untergeordneten Elementen ausgelöst werden, z. B. innerhalb eines zusammengesetzten Steuerelements.

Routingereignislistener benötigen nicht die Routingereignisse, die sie behandeln, um Mitglieder ihrer Klasse zu sein. Jeder UIElement oder ContentElement kann ein Ereignis-Listener für jedes Routingereignis sein. Da visuelle Elemente von UIElement oder ContentElementabgeleitet werden, können Sie Routingereignisse als konzeptionelle "Schnittstelle" verwenden, die den Austausch von Ereignisinformationen zwischen unterschiedlichen Elementen in einer Anwendung unterstützt. Das "Interface"-Konzept für Routingereignisse gilt insbesondere für Eingabeereignisse.

Routingereignisse unterstützen den Austausch von Ereignisinformationen zwischen Elementen entlang der Ereignisroute, da jeder Listener Zugriff auf dieselbe Instanz von Ereignisdaten hat. Wenn ein Element etwas in den Ereignisdaten ändert, ist diese Änderung für nachfolgende Elemente in der Ereignisroute sichtbar.

Abgesehen vom Routingaspekt können Sie aus folgenden Gründen ein routingfähiges Ereignis anstelle eines standardmäßigen CLR-Ereignisses implementieren:

  • Einige WPF-Formatierungs- und Vorlagenfeatures, z. B. EventSetters und EventTriggers, erfordern das referenzierte Ereignis als Routingereignis.

  • Routingereignisse unterstützen Klassenereignishandler , die ein Ereignis vor allen Instanzhandlern für dasselbe Ereignis in jeder Instanz der Listenerklasse behandeln. Dieses Feature ist beim Steuerelemententwurf nützlich, da ihr Klassenhandler ereignisgesteuerte Klassenverhalten erzwingen kann, die nicht versehentlich von einem Instanzhandler unterdrückt werden können.

Anfügen und Implementieren eines Handlers für ein geroutetes Ereignis

In XAML fügen Sie einen Ereignishandler an ein Element an, indem Sie den Ereignisnamen als Attribut für das Ereignislistenerelement deklarieren. Der Attributwert ist der Name der Handlermethode. Die Handlermethode muss in der Code-Behind partiellen Klasse für die XAML-Seite implementiert werden. Der Ereignislistener ist das Element, an das der Ereignishandler angefügt und aufgerufen wird.

Für ein Ereignis, das ein Mitglied (geerbt oder anderweitig) der Listenerklasse ist, können Sie einen Handler wie folgt anfügen:

<Button Name="Button1" Click="Button_Click">Click me</Button>

Wenn das Ereignis kein Mitglied der Listenerklasse ist, müssen Sie den qualifizierten Ereignisnamen in Form von <owner type>.<event name>. Um einen Handler an ein StackPanel für ein Click Ereignis anzubinden, das zu diesem Element aufsteigt, und da die StackPanel Klasse das Click Ereignis nicht implementiert, müssen Sie die qualifizierte Ereignisnamensyntax verwenden.

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

Die Signatur der Ereignishandlermethode im CodeBehind muss mit dem Delegattyp für das Routingereignis übereinstimmen. Der sender Parameter des Delegaten RoutedEventHandler für das Click Ereignis gibt das Element an, an das der Ereignishandler angefügt ist. Der args Parameter des RoutedEventHandler Delegaten enthält die Ereignisdaten. Eine kompatible Code-Behind-Implementierung für den Button_Click Ereignishandler könnte zum Beispiel so aussehen:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Click event logic.
}
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    ' Click event logic.
End Sub

Obwohl RoutedEventHandler der grundlegende Delegat für Ereignishandhabung im Routing ist, benötigen einige Steuerelemente oder Implementierungsszenarien unterschiedliche Delegaten, die spezialisiertere Ereignisdaten unterstützen. Beispielsweise sollte der Handler für das DragEnter Routingereignis den DragEventHandler Delegaten implementieren. Dadurch kann der Handlercode auf die DragEventArgs.Data Eigenschaft in Ereignisdaten zugreifen, die die Nutzlast der Zwischenablagedaten des Ziehvorgangs enthält.

Die XAML-Syntax zum Hinzufügen von Routingereignishandlern ist identisch mit den standardmäßigen CLR-Ereignishandlern. Weitere Informationen zum Hinzufügen von Ereignishandlern in XAML finden Sie unter XAML in WPF. Ein vollständiges Beispiel dafür, wie Sie einen Ereignishandler an ein Element mit XAML anfügen, finden Sie unter How to handle a Routed Event

Zum Anfügen eines Ereignishandlers für ein routingfähiges Ereignis an ein Element mit Code haben Sie im Allgemeinen zwei Optionen:

  • Rufen Sie die AddHandler Methode direkt auf. Routed-Event-Handler können immer auf diese Weise angefügt werden. In diesem Beispiel wird mithilfe der AddHandler Methode ein Click Ereignishandler an eine Schaltfläche angefügt:

    Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    

    So fügen Sie einen Handler für das Ereignis der Schaltfläche Click einem anderen Element in der Route des Ereignisses hinzu, z. B. einem StackPanel benannten StackPanel1:

    StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    
  • Wenn das Routingereignis einen CLR-Ereigniswrapper implementiert, verwenden Sie sprachspezifische Ereignissyntax, um Ereignishandler wie für ein standardmäßiges CLR-Ereignis hinzuzufügen. Die meisten vorhandenen WPF-Routingereignisse implementieren den CLR-Wrapper, was die Verwendung einer sprachspezifischen Ereignissyntax ermöglicht. In diesem Beispiel wird ein Click Ereignishandler mithilfe einer sprachspezifischen Syntax an eine Schaltfläche angefügt:

    Button1.Click += Button_Click;
    
    AddHandler Button1.Click, AddressOf Button_Click
    

Ein Beispiel zum Anfügen eines Ereignishandlers im Code finden Sie unter Hinzufügen eines Ereignishandlers mithilfe von Code. Wenn Sie in Visual Basic codieren, können Sie auch das Handles Schlüsselwort verwenden, um Handler als Teil der Handlerdeklarationen hinzuzufügen. Weitere Informationen finden Sie unter Visual Basic und WPF-Ereignisbehandlung.

Das Konzept der Handhabung

Alle Routingereignisse verwenden eine gemeinsame Basisklasse für Ereignisdaten, die die RoutedEventArgs Klasse ist. Die RoutedEventArgs Klasse definiert die boolesche Handled Eigenschaft. Der Zweck der Handled Eigenschaft besteht darin, jedem Ereignishandler entlang der Ereignisroute das Markieren des Routingereignisses als behandelt zu ermöglichen. Um ein Ereignis als behandelt zu markieren, legen Sie im Ereignishandlercode den Wert von Handled auf true fest.

Der Wert von Handled beeinflusst die Verarbeitung eines routierten Ereignisses, wenn es die Ereignisroute entlangläuft. Wenn Handled in den geteilten Ereignisdaten eines Routingereignisses als true vorhanden ist, werden Handler, die weiter entlang der Ereignisroute an andere Elemente angefügt sind, normalerweise nicht für diese bestimmte Ereignisinstanz aufgerufen. Bei den meisten gängigen Handlerszenarien bewirkt das Markieren eines Ereignisses als behandelt, dass nachfolgende Handler entlang der Ereignisroute, unabhängig davon, ob es sich um Instanz- oder Klassenhandler handelt, nicht auf diese bestimmte Ereignisinstanz reagieren. In seltenen Fällen, in denen Sie den Ereignishandler benötigen, um auf Routingereignisse zu reagieren, die als behandelt gekennzeichnet wurden, können Sie:

Das Konzept könnte Auswirkungen darauf haben, wie Sie Ihre Anwendung entwerfen und Ihre Ereignishandler implementieren. Sie können Handled als ein einfaches Protokoll für die Verarbeitung von Routing-Ereignissen konzeptualisieren. Wie Sie dieses Protokoll verwenden, liegt bei Ihnen, aber die erwartete Verwendung des Handled Parameters lautet:

  • Wenn ein routingfähiges Ereignis als behandelt markiert ist, muss es nicht erneut von anderen Elementen entlang der Route behandelt werden.

  • Wenn ein routingfähiges Ereignis nicht als behandelt gekennzeichnet ist, verfügen Listener weiter oben in der Ereignisroute nicht über einen Handler für das Ereignis, oder keine der registrierten Handler hat auf das Ereignis in einer Weise geantwortet, die das Markieren des Ereignisses als behandelt angibt. Handler für den aktuellen Listener verfügen über drei mögliche Aktionskurse:

    • Ergreifen Sie überhaupt keine Aktion. Das Ereignis bleibt unbehandelt und wird an den nächsten Listener in der Baumstruktur weitergereicht.

    • Führen Sie Code als Reaktion auf das Ereignis aus, jedoch nicht in einem Umfang, der die Kennzeichnung des Ereignisses als behandelt rechtfertigen würde. Das Ereignis bleibt unbehandelt und wird zum nächsten Listener im Baum weitergeleitet.

    • Führen Sie Code als Reaktion auf das Ereignis aus, so dass das Markieren des Ereignisses als verarbeitet gerechtfertigt ist. Markieren Sie das Ereignis als behandelt in den Ereignisdaten. Das Ereignis wird weiterhin an den nächsten Listener in der Struktur weitergeleitet, aber die meisten Listener werden keine weiteren Handler aufrufen. Die Ausnahme sind Listener mit Handlern, die speziell mit handledEventsToo auf true registriert wurden.

Weitere Informationen zum Behandeln von Routingereignissen finden Sie unter Kennzeichnen von Routingereignissen als behandelt und Klassenbehandlung.

Obwohl Entwickler, die nur ein bubbelndes Routing-Ereignis für das Objekt behandeln, das es ausgelöst hat, sich möglicherweise keine Sorgen um andere Listener machen, empfiehlt es sich, das Ereignis trotzdem als behandelt zu markieren. Dies verhindert unerwartete Nebenwirkungen, wenn ein Element weiter entlang der Ereignisroute über einen Handler für dasselbe Routingereignis verfügt.

Klassen-Manager

Bei Routingereignishandlern kann es sich um Instanzhandler oder Klassenhandler handeln. Klassenhandler für eine bestimmte Klasse werden vor jedem Instanzhandler aufgerufen, der auf dasselbe Ereignis in einer Instanz dieser Klasse reagiert. Wenn Routingereignisse als behandelt markiert werden, erfolgt diese Markierung aufgrund dieses Verhaltens häufig innerhalb von Klassenhandlern. Es gibt zwei Typen von Klassenhandlern:

  • Statische Klassenereignishandler, die durch Aufrufen der RegisterClassHandler-Methode innerhalb eines statischen Klassenkonstruktors registriert werden
  • Überschreibende Klassenereignishandler, die durch Überschreiben (Außerkraftsetzen) der virtuellen Ereignismethoden der Basisklasse registriert werden Virtuelle Ereignismethoden der Basisklasse sind in erster Linie für Eingabeereignisse vorhanden und weisen Namen auf, die mit On<Ereignisname> und OnPreview<Ereignisname> beginnen.

Einige WPF-Steuerelemente weisen eine inhärente Klassenbehandlung für bestimmte Routingereignisse auf. Die Klassenbehandlung kann das äußere Aussehen verleihen, dass das routingfähige Ereignis nie ausgelöst wird, aber tatsächlich wird es von einem Klassenhandler als behandelt markiert. Wenn Ihr Ereignishandler auf das behandelte Ereignis reagieren soll, können Sie Ihren Handler registrieren, indem Sie handledEventsToo auf true setzen. Weitere Informationen zum Implementieren eigener Klassenhandler oder zum Umgehen unerwünschter Klassenbehandlungen finden Sie unter Markieren von Routingereignissen als behandelt und Klassenbehandlung.

Angefügte Ereignisse in WPF

Die XAML-Sprache definiert auch einen speziellen Ereignistyp, der als angefügtes Ereignis bezeichnet wird. Angefügte Ereignisse können verwendet werden, um ein neues Routingereignis in einer Nicht-Elementklasse zu definieren und dieses Ereignis für jedes Element in Ihrer Struktur auszulösen. Dazu müssen Sie das angefügte Ereignis als Routingereignis registrieren und spezifischen Sicherungscode bereitstellen, der angefügte Ereignisfunktionen unterstützt. Da angefügte Ereignisse als Routingereignisse registriert sind, verbreiten sie sich, wenn sie auf einem Element ausgelöst werden, durch den Elementbaum.

In der XAML-Syntax wird ein angefügtes Ereignis durch seinen Ereignisnamen und den Besitzertyp in der Form von <owner type>.<event name> angegeben. 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 entlang der Ereignisroute an ein beliebiges Element angefügt werden. Sie können auch Handler für angefügte Ereignisse im CodeBehind anfügen, indem Sie die AddHandler Methode für das Objekt aufrufen, an das der Handler angefügt werden soll.

Das WPF-Eingabesystem verwendet häufig angefügte Ereignisse. Fast alle angefügten Ereignisse werden jedoch als gleichwertige nicht angefügte Routingereignisse über Basiselemente angezeigt. Sie werden angefügte Ereignisse nur selten direkt verwenden oder behandeln. So ist es beispielsweise einfacher, das zugrunde liegende angefügte Mouse.MouseDown Ereignis für ein UIElement über das entsprechende UIElement.MouseDown geroutete Ereignis zu behandeln, als dies mithilfe der angefügten Ereignissyntax in XAML oder Code-Behind zu tun.

Weitere Informationen zu angefügten Ereignissen in WPF finden Sie in der Übersicht über angefügte Ereignisse.

Qualifizierte Ereignisnamen in XAML

Die <owner type>.<event name> Syntax weist einem Ereignisnamen den Namen seines Eigentümertyps zu. Mit dieser Syntax kann ein Ereignis an jedes Element angefügt werden, nicht nur Elemente, die das Ereignis als Mitglied ihrer Klasse implementieren. Die Syntax gilt beim Anfügen von Handlern in XAML für angefügte Ereignisse oder Routingereignisse für beliebige Elemente entlang der Ereignisroute. Berücksichtigen Sie das Szenario, in dem Sie einen Handler an ein übergeordnetes Element anfügen möchten, um Routingereignisse zu behandeln, die für untergeordnete Elemente ausgelöst werden. Wenn das übergeordnete Element nicht über das Routingereignis als Mitglied verfügt, müssen Sie die qualifizierte Ereignisnamensyntax verwenden. Beispiel:

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

Im Beispiel ist der übergeordnete Elementlistener, dem der Ereignishandler hinzugefügt wird, ein StackPanel. Das Click Routingereignis wird jedoch für die ButtonBase Klasse implementiert und ausgelöst und ist für die Button Klasse durch Vererbung verfügbar. Obwohl die Button-Klasse das Click-Ereignis hat, erlaubt das Routed-Event-System Handler für jedes geroutete Ereignis an jeden beliebigen UIElement- oder ContentElement-Instanzlistener anzuhängen, der andernfalls Handler für ein CLR-Ereignis enthalten könnte. Der Standardnamespace für diese qualifizierten Ereignisattributenamen ist in der Regel der Standard-WPF-Namespace xmlnsxmlns , Sie können jedoch auch präfixierte Namespaces für benutzerdefinierte Routingereignisse angeben. Weitere Informationen zu xmlnsfinden Sie unter XAML-Namespaces und Namespacezuordnung für WPF-XAML

WPF-Eingabeereignisse

Eine häufige Anwendung von gerouteten Ereignissen innerhalb der WPF-Plattform ist die Steuerung von Eingabeereignissen.

WPF-Eingabeereignisse, die paarweise auftreten, werden so implementiert, dass eine einzelne Benutzeraktion von einem Eingabegerät, z. B. das Drücken einer Maustaste, die Vorschau- und Bubbling-Ereignisse in Folge auslöst. Zuerst wird das Vorschauereignis ausgelöst und die Route abgeschlossen. Nach Abschluss des Vorschauereignisses wird das Bubbling-Ereignis ausgelöst und vervollständigt seine Route. Der RaiseEvent Methodenaufruf in der implementierenden Klasse, die das Bubbling-Ereignis auslöst, verwendet die Ereignisdaten aus dem Vorschauereignis für das Bubbling-Ereignis wieder.

Ein vorschaufähiges Eingabeereignis, das als behandelt gekennzeichnet ist, ruft keine normalerweise registrierten Ereignishandler für den Rest der Vorschauroute auf, und das gekoppelte Bubbling-Ereignis wird nicht ausgelöst. Dieses Behandlungsverhalten ist nützlich für zusammengesetzte Steuerelemente-Designer, die Treffertest-basierte Eingabeereignisse oder fokusbasierte Eingabeereignisse auf oberster Ebene ihres Steuerelements melden möchten. Elemente der obersten Ebene des Steuerelements haben die Möglichkeit, Vorschauereignisse von Steuerelementunterkomponenten zu behandeln, um sie durch ein steuerelementspezifisches Ereignis auf oberster Ebene zu "ersetzen".

Um zu veranschaulichen, wie die Verarbeitung von Eingabeereignissen funktioniert, betrachten Sie das folgende Eingabeereignisbeispiel. In der folgenden Strukturdarstellung leaf element #2 ist die Quelle der ereignisse und PreviewMouseDownMouseDown der paarten Ereignisse:

Ein Diagramm, das zeigt, wie das Ereignisrouting von einem Stammelement zu anderen Elementen fließt.

Die Reihenfolge der Ereignisverarbeitung nach einer Maus-abwärts-Aktion für blattelement #2 lautet:

  1. PreviewMouseDown Tunnelereignis für das Stammelement.
  2. PreviewMouseDown Tunnelereignis für Zwischenelement #1.
  3. PreviewMouseDown Tunneling-Ereignis für das Blattelement #2, das das Quellelement ist.
  4. MouseDown Bubbling-Ereignis für Blattelement #2, bei dem es sich um das Quellelement handelt.
  5. MouseDown Bubbling-Ereignis für Zwischenelement #1.
  6. MouseDown Bubbling-Ereignis für das Stammelement.

Der Delegierte für Routingsereignisse stellt Verweise auf das Objekt bereit, das das Ereignis ausgelöst, und auf das Objekt, wo der Handler aufgerufen wurde. Das Objekt, das das Ereignis ursprünglich ausgelöst hat, wird von der Source Eigenschaft in den Ereignisdaten gemeldet. Das Objekt, in dem der Handler aufgerufen wurde, wird vom Absenderparameter gemeldet. Bei einer bestimmten Instanz eines Routingereignisses ändert sich das Objekt, das das Ereignis ausgelöst hat, nicht, während das Ereignis durch die Elementhierarchie wandert, aber der sender schon. In den Schritten 3 und 4 des vorherigen Diagramms sind die Source und sender dasselbe Objekt.

Wenn der Eingabeereignishandler die anwendungsspezifische Logik abschließt, die zum Adressieren des Ereignisses erforderlich ist, sollten Sie das Eingabeereignis als behandelt markieren. Wenn ein Eingabeereignis markiert Handledist, werden Handler entlang der Ereignisroute normalerweise nicht aufgerufen. Eingabeereignishandler, die mit dem handledEventsToo Parametersatz true registriert sind, werden jedoch auch dann aufgerufen, wenn das Ereignis als behandelt markiert wird. Weitere Informationen finden Sie unter Vorschauereignisse und Markieren von gerouteten Ereignissen als behandelt und Klassenbehandlung.

Das Konzept der Vorschau- und Bubbling-Ereignispaare mit freigegebenen Ereignisdaten und sequenziellem Auslösen des Vorschauereignisses und des Bubbling-Ereignisses gilt nur für einige WPF-Eingabeereignisse und nicht für alle Routingereignisse. Wenn Sie Ihr eigenes Eingabeereignis implementieren, um ein erweitertes Szenario zu behandeln, sollten Sie den WPF-Eingabeereignispaaransatz verfolgen.

Wenn Sie ein eigenes zusammengesetztes Steuerelement implementieren, das auf Eingabeereignisse reagiert, sollten Sie die Verwendung von Vorschauereignissen verwenden, um Eingabeereignisse zu unterdrücken und zu ersetzen, die für Unterkomponenten ausgelöst werden, durch ein Ereignis der obersten Ebene, das das vollständige Steuerelement darstellt. Weitere Informationen finden Sie unter Markierung von routingspezifischen Ereignissen als behandelt und Klassenhandhabung.

Weitere Informationen zum WPF-Eingabesystem und zur Interaktion von Eingaben und Ereignissen in typischen Anwendungsszenarien finden Sie unter Input Overview

EventSetters und EventTriggers

In Markupstilen können vordefinierte XAML-Ereignisbehandlungssyntax mithilfe einer EventSetter eingeschlossen werden. Wenn der XAML-Code verarbeitet wird, wird der gestalteten Instanz der referenzierte Handler hinzugefügt. Sie können nur ein EventSetter Routingereignis deklarieren. Im folgenden Beispiel wird die referenzierte ApplyButtonStyle Ereignishandlermethode in CodeBehind implementiert.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}">
            <EventSetter Event="Click" Handler="ApplyButtonStyle"/>
        </Style>
    </StackPanel.Resources>
    <Button>Click me</Button>
    <Button Click="Button_Click">Click me</Button>
</StackPanel>

Wahrscheinlich enthält der Style Knoten bereits andere Formatvorlageninformationen, die sich auf Steuerelemente des angegebenen Typs beziehen, und wenn der EventSetter Knoten Teil dieser Formatvorlagen ist, wird die Codewiederverwendung sogar auf Markupebene gefördert. Außerdem werden Methodennamen für Handler EventSetter abstrahiert, sodass sie von der allgemeinen Anwendung und dem Seitenmarkup getrennt sind.

Eine weitere spezielle Syntax, die die Routingereignis- und Animationsfeatures von WPF kombiniert, ist eine EventTrigger. Wie bei EventSetter können Sie nur ein EventTrigger für ein weitergeleitetes Ereignis deklarieren. In der Regel wird eine EventTrigger als Teil einer Formatvorlage deklariert, aber eine EventTrigger kann bei Elemente auf Seitenebene als Teil der Triggers Sammlung oder in einem ControlTemplate deklariert werden. "EventTrigger ermöglicht es Ihnen, ein Storyboard festzulegen, das immer dann ausgeführt wird, wenn ein routingfähiges Ereignis ein Element in seiner Route erreicht, das ein EventTrigger für dieses Ereignis deklariert." Der Vorteil eines EventTrigger anstatt nur das Ereignis zu behandeln und ein vorhandenes Storyboard auszulösen, besteht darin, dass ein EventTrigger eine bessere Kontrolle über das Storyboard und sein Laufzeitverhalten bietet. Weitere Informationen finden Sie unter Verwenden von Ereignistriggern zum Steuern eines Storyboards nach dem Start

Weitere Informationen zu weitergeleiteten Ereignissen

Sie können die Konzepte und Anleitungen in diesem Artikel als Ausgangspunkt beim Erstellen von benutzerdefinierten Routingereignissen in Ihren eigenen Klassen verwenden. Sie können Ihre benutzerdefinierten Ereignisse auch mit speziellen Ereignisdatenklassen und Delegaten unterstützen. Ein Routenereignisbesitzer kann jede beliebige Klasse sein, aber routingfähige Ereignisse müssen von Klassen abgeleitet von UIElement oder ContentElement ausgelöst und behandelt werden, um nützlich zu sein. Weitere Informationen zu benutzerdefinierten Ereignissen finden Sie unter Erstellen eines benutzerdefinierten Routingereignisses.

Siehe auch