Übersicht über Ereignisse und Routingereignisse

Wichtige APIs

Wir beschreiben das Programmierkonzept von Ereignissen in einer WinUI-App bei Verwendung von XAML für Ihre UI-Definition. Sie können Handler für Ereignisse als Teil der Deklarationen für UI-Elemente in XAML zuweisen, oder Sie können die Handler im Code hinzufügen. Windows-Runtime unterstützt Routingereignisse: Bestimmte Eingabeereignisse und Datenereignisse können von Objekten behandelt werden, die über das Objekt hinausgehen, das das Ereignis ausgelöst hat. Routingereignisse sind nützlich, wenn Sie Steuerelementvorlagen definieren oder Seiten oder Layoutcontainer verwenden.

Hinweis

C# und C++/WinRT werden sowohl für WinUI 3/Windows App SDK- als auch für UWP-Apps unterstützt. C++/CX gilt nur für UWP und wird für WinUI 3 nicht unterstützt.

Ereignisse als Programmierkonzept

Im Allgemeinen ähneln Ereigniskonzepte beim Programmieren einer WinUI-App dem Ereignismodell in den meisten gängigen Programmiersprachen. Wenn Sie bereits wissen, wie Sie mit Microsoft .NET- oder C++-Ereignissen arbeiten, haben Sie einen Vorsprung. Aber Sie müssen nicht viel über Konzepte des Ereignismodells wissen, um einige grundlegende Aufgaben wie das Anfügen von Handlern auszuführen.

Wenn Sie eine WinUI -App (oder UWP) erstellen, wird die Benutzeroberfläche im Markup (XAML) definiert. In der XAML-Markupsyntax ähneln einige Prinzipien der Verbindung von Ereignissen zwischen Markupelementen und Laufzeitcodeentitäten anderen Webtechnologien, z. B. ASP.NET oder HTML5.

Hinweis

Der Code, der die Laufzeitlogik für eine XAML-definierte Benutzeroberfläche bereitstellt, wird häufig als CodeBehind oder codeBehind-Datei bezeichnet. In den Microsoft Visual Studio-Projektmappenansichten wird diese Beziehung grafisch dargestellt, wobei die CodeBehind-Datei eine abhängige und geschachtelte Datei im Vergleich zur XAML-Seite ist, auf die verwiesen wird.

Button.Click: Einführung in Ereignisse und XAML

Eine der am häufigsten verwendeten Programmieraufgaben für eine WinUI-App besteht darin, Benutzereingaben auf der Benutzeroberfläche zu erfassen. Ihre Benutzeroberfläche kann z. B. über eine Schaltfläche verfügen, auf die der Benutzer klicken muss, um Informationen zu senden oder den Zustand zu ändern.

Sie definieren die Benutzeroberfläche für Ihre WinUI-App, indem Sie XAML generieren. Dieser XAML-Code ist in der Regel die Ausgabe einer Entwurfsoberfläche in Visual Studio. Sie können den XAML-Code auch in einem Nur-Text-Editor oder einem XAML-Editor eines Drittanbieters schreiben. Beim Generieren dieses XAML können Sie Ereignishandler für einzelne UI-Elemente gleichzeitig verbinden, mit denen Sie alle anderen XAML-Attribute definieren, die Eigenschaftswerte dieses UI-Elements festlegen.

Um die Ereignisse in XAML zu verbinden, geben Sie den Zeichenfolgennamen der Handlermethode an, die Sie bereits definiert haben oder später in Ihrer Code-Behind-Datei definieren. Dieser XAML-Code definiert z. B. ein Button-Objekt mit anderen Eigenschaften (x:Name-Attribut, Content), die als Attribute zugewiesen sind, und verkabelt einen Handler für das Click-Ereignis der Schaltfläche, indem auf eine Methode mit dem Namen verwiesen wird ShowUpdatesButton_Click:

<Button x:Name="showUpdatesButton"
  Content="{Binding ShowUpdatesText}"
  Click="ShowUpdatesButton_Click"/>

Tipp

Die Ereignisverkabelung ist ein Programmierbegriff. Er bezieht sich auf den Prozess oder Code, bei dem Sie angeben, dass Vorkommen eines Ereignisses eine benannte Handlermethode aufrufen sollen. Bei den meisten prozeduralen Codemodellen handelt es sich bei der Ereignisverkabelung um impliziten oder expliziten "AddHandler"-Code, der sowohl das Ereignis als auch die Methode benennt und in der Regel eine Zielobjektinstanz umfasst. In XAML ist „AddHandler“ implizit und die Ereignisverknüpfung umfasst nur das Benennen des Ereignisses als Attributnamen eines Objektelement und das Benennen des Handlers als Wert dieses Attributs.

Sie schreiben den tatsächlichen Handler in der Programmiersprache, die Sie für den gesamten Code und das Code-Behind Ihrer App verwenden. Mit dem Attribut Click="ShowUpdatesButton_Click" haben Sie einen Vertrag erstellt, der beim Kompilieren und Analysieren von XAML-Markup sowohl im XAML-Markupkompilierungsschritt der Build-Aktion Ihrer IDE als auch bei der späteren XAML-Analyse beim Laden der App eine Methode mit dem Namen ShowUpdatesButton_Click als Teil des App-Codes finden kann. ShowUpdatesButton_Click muss eine Methode sein, die eine kompatible Methodensignatur (basierend auf einem Delegaten) für jeden Handler des Click-Ereignisses implementiert. Dieser Code definiert z. B. den ShowUpdatesButton_Click Handler.

private void ShowUpdatesButton_Click (object sender, RoutedEventArgs e) 
{
    Button b = sender as Button;
    //more logic to do here...
}
void winrt::MyNamespace::implementation::BlankPage::ShowUpdatesButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    auto b{ sender.as<Microsoft::UI::Xaml::Controls::Button>() };
    // More logic to do here.
}
void MyNamespace::BlankPage::ShowUpdatesButton_Click(Platform::Object^ sender, Microsoft::UI::Xaml::RoutedEventArgs^ e) 
{
    Button^ b = (Button^) sender;
    //more logic to do here...
}

In diesem Beispiel basiert die ShowUpdatesButton_Click Methode auf dem RoutedEventHandler-Delegaten . Sie wissen, dass dies der zu verwendende Delegat ist, da dieser Delegat in der Syntax für die Click-Methode angezeigt wird.

Tipp

Visual Studio bietet eine bequeme Möglichkeit, den Ereignishandler zu benennen und die Handlermethode beim Bearbeiten von XAML zu definieren. Wenn Sie den Attributnamen des Ereignisses im XAML-Text-Editor angeben, warten Sie einen Moment, bis eine Microsoft IntelliSense-Liste angezeigt wird. Wenn Sie in der Liste auf "Neuer Ereignishandler<" klicken>, schlägt Microsoft Visual Studio einen Methodennamen basierend auf dem x:Name (oder Typnamen) des Elements, dem Ereignisnamen und einem numerischen Suffix vor. Sie können dann mit der rechten Maustaste auf den ausgewählten Ereignishandlernamen klicken und auf "Zu Ereignishandler navigieren" klicken. Dadurch wird direkt zur neu eingefügten Ereignishandlerdefinition navigiert, wie in der Code-Editor-Ansicht der CodeBehind-Datei für die XAML-Seite zu sehen ist. Der Ereignishandler verfügt bereits über die richtige Signatur, einschließlich des Absenderparameters und der Ereignisdatenklasse, die das Ereignis verwendet. Wenn in Ihrem CodeBehind bereits eine Handlermethode mit der richtigen Signatur vorhanden ist, wird der Name dieser Methode zusammen mit der Option <Neuer Ereignishandler> in der Dropdownliste „AutoVervollständigen“ angezeigt. Sie können auch die TAB-TASTE als Verknüpfung drücken, anstatt auf die IntelliSense-Listenelemente zu klicken.

Definieren eines Ereignishandlers

Für Objekte, die UI-Elemente darstellen und in XAML deklariert werden, wird Ereignishandlercode in der partiellen Klasse definiert, die als CodeBehind für eine XAML-Seite fungiert. Ereignishandler sind Methoden, die Sie als Teil der partiellen Klasse schreiben, die Ihrem XAML zugeordnet ist. Diese Ereignishandler basieren auf den Delegaten, die ein bestimmtes Ereignis verwendet. Ihre Ereignishandlermethoden können öffentlich oder privat sein. Der private Zugriff funktioniert, da der vom XAML erstellte Handler und die instanz letztendlich von der Codegenerierung verknüpft werden. Im Allgemeinen wird empfohlen, die Ereignishandlermethoden in der Klasse öffentlich zu machen.

Hinweis

Ereignishandler für C++ werden nicht in partiellen Klassen definiert, sondern als privates Klassenmitglied in der Header-Datei deklariert. Die Buildaktionen für ein C++-Projekt kümmern sich um das Generieren von Code, der das XAML-Typsystem und das CodeBehind-Modell für C++ unterstützt.

Der Absenderparameter und die Ereignisdaten

Der für das Ereignis geschriebene Handler kann auf zwei Werte zugreifen, die als Eingabe für jeden Fall verfügbar sind, in dem der Handler aufgerufen wird. Der erste solche Wert ist Absender, bei dem es sich um einen Verweis auf das Objekt handelt, an das der Handler angefügt ist. Der Sender-Parameter wird als Basisobjekttyp eingegeben. Eine gängige Technik ist das Umwandeln des Absenders in einen präziseren Typ. Diese Technik ist nützlich, wenn Sie erwarten, dass der Status des Absenderobjekts selbst überprüft oder geändert wird. Basierend auf Ihrem eigenen App-Design kennen Sie normalerweise einen Typ, auf den der Absender sicher umgewandelt werden kann, basierend auf der Stelle, an der der Handler registriert ist, oder anderen Design-Spezifika.

Der zweite Wert ist Ereignisdaten, die in der Regel in Syntaxdefinitionen als e (oder args)-Parameter angezeigt werden. Sie können ermitteln, welche Eigenschaften für Ereignisdaten verfügbar sind, indem Sie sich den e-Parameter des Delegaten ansehen, der für das jeweilige Ereignis zugewiesen ist, das Sie behandeln, und dann IntelliSense oder Objektbrowser in Visual Studio verwenden. Sie können auch die Referenzdokumentation für Windows-Runtime verwenden.

Bei einigen Ereignissen sind die spezifischen Eigenschaftswerte der Ereignisdaten so wichtig wie zu wissen, dass das Ereignis aufgetreten ist. Dies gilt insbesondere für die Eingabeereignisse. Bei Zeigerereignissen kann die Position des Zeigers, wenn das Ereignis aufgetreten ist, wichtig sein. Bei Tastaturereignissen löst jeder mögliche Tastendruck ein KeyDown- und KeyUp-Ereignis aus. Um zu ermitteln, welche Taste ein Benutzer gedrückt hat, müssen Sie auf die KeyRoutedEventArgs zugreifen, die für den Ereignishandler verfügbar ist. Weitere Informationen zum Behandeln von Eingabeereignissen finden Sie unter Tastaturinteraktionen und Behandeln von Zeigereingaben. Eingabeereignisse und Eingabeszenarien weisen häufig zusätzliche Überlegungen auf, die in diesem Thema nicht behandelt werden, z. B. Zeigererfassung für Zeigerereignisse sowie Modifizierertasten und Plattformtastencodes für Tastaturereignisse.

Ereignishandler, die das asynchrone Muster verwenden

In einigen Fällen sollten Sie APIs verwenden, die ein asynchrones Muster in einem Ereignishandler verwenden. Sie können beispielsweise eine Schaltfläche in einer App-Leiste verwenden, um eine Dateiauswahl anzuzeigen und damit zu interagieren. Viele der Dateiauswahl-APIs sind jedoch asynchron. Sie müssen innerhalb eines asynchronen/awaitablen Bereichs aufgerufen werden, und der Compiler erzwingt dies. Sie können also dem Ereignishandler das asynchrone Schlüsselwort hinzufügen, sodass der Handler jetzt asynchronleer ist. Jetzt ist der Ereignishandler berechtigt, asynchrone/awaitable Aufrufe auszuführen.

Hinzufügen von Ereignishandlern im Code

XAML ist nicht die einzige Möglichkeit, einem Objekt einen Ereignishandler zuzuweisen. Zum Hinzufügen von Ereignishandlern zu einem bestimmten Objekt im Code, einschließlich Objekten, die in XAML nicht verwendet werden können, können Sie die sprachspezifische Syntax zum Hinzufügen von Ereignishandlern verwenden.

In C# ist die Syntax, den +=-Operator zu verwenden. Sie registrieren den Handler, indem Sie auf den Namen der Ereignishandlermethode auf der rechten Seite des Operators verweisen.

Wenn Sie Code verwenden, um Ereignishandler zu Objekten hinzuzufügen, die in der Laufzeitbenutzeroberfläche angezeigt werden, empfiehlt es sich, solche Handler als Reaktion auf ein Objektlebensdauer-Ereignis oder einen Rückruf hinzuzufügen, z. B. "Loaded " oder " OnApplyTemplate", damit die Ereignishandler für das relevante Objekt zur Laufzeit für vom Benutzer initiierte Ereignisse bereit sind. Dieses Beispiel zeigt eine XAML-Gliederung der Seitenstruktur und stellt dann die C#-Sprachsyntax zum Hinzufügen eines Ereignishandlers zu einem Objekt bereit.

<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
  <StackPanel>
    <TextBlock Name="textBlock1">Put the pointer over this text</TextBlock>
...
  </StackPanel>
</Grid>
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += textBlock1_PointerEntered;
    textBlock1.PointerExited += textBlock1_PointerExited;
}

Hinweis

Eine ausführlichere Syntax ist vorhanden. Im Jahr 2005 hat C# ein Feature namens Delegatinference hinzugefügt, das es einem Compiler ermöglicht, die neue Delegatinstanz zu ableiten und die vorherige, einfachere Syntax zu aktivieren. Die Funktion der ausführlichen Syntax entspricht dem vorherigen Beispiel. Vor der Registrierung wird jedoch explizit eine neue Delegatinstanz erstellt. Der Delegatrückschluss wird somit nicht genutzt. Diese explizite Syntax ist weniger häufig, sie wird jedoch in einigen Codebeispielen möglicherweise noch angezeigt.

void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += new PointerEventHandler(textBlock1_PointerEntered);
    textBlock1.PointerExited += new MouseEventHandler(textBlock1_PointerExited);
}

In C++/CX verwenden Sie auch die += Syntax, aber es gibt Unterschiede vom einfachen C#-Formular:

  • Es gibt keine Delegatenableitung, daher müssen Sie ref new für eine Delegateninstanz verwenden.
  • Der Delegatkonstruktor hat zwei Parameter und erfordert das Zielobjekt als ersten Parameter. In der Regel geben Sie dies an.
  • Der Delegatenkonstruktor erfordert die Methodenadresse als zweiten Parameter, sodass der Referenzoperator & dem Methodennamen vorausgeht.
textBlock1().PointerEntered({this, &MainPage::TextBlock1_PointerEntered });
textBlock1->PointerEntered += 
ref new PointerEventHandler(this, &BlankPage::textBlock1_PointerEntered);

Entfernen von Ereignishandlern im Code

Es ist in der Regel nicht erforderlich, Ereignishandler im Code zu entfernen, auch wenn Sie sie im Code hinzugefügt haben. Das Objektlebensdauerverhalten für die meisten Windows-Runtime-Objekte wie Seiten und Steuerelemente zerstört die Objekte, wenn sie vom Hauptfenster und der visuellen Struktur getrennt werden, und alle Stellvertretungsverweise werden ebenfalls zerstört. .NET führt dies durch die Garbage Collection durch und Windows-Runtime mit C++/CX verwendet standardmäßig schwache Verweise.

Es gibt einige seltene Fälle, in denen Sie Ereignishandler explizit entfernen möchten. Dazu gehören:

  • Für statische Ereignisse hinzugefügte Handler, für die keine konventionelle Garbage Collection durchgeführt werden kann. Die Ereignisse der Klassen CompositionTarget und Clipboard sind Beispiele für statische Ereignisse in der Windows-Runtime-API.
  • Testen Sie Code, in dem der Zeitpunkt der Entfernung des Handlers sofort angezeigt werden soll, oder Code, in dem Sie alte/neue Ereignishandler für ein Ereignis zur Laufzeit austauschen möchten.
  • Die Implementierung eines benutzerdefinierten remove-Accessors.
  • Benutzerdefinierte statische Ereignisse.
  • Handler für Seitennavigation.

"FrameworkElement.Unloaded " oder "Page.NavigatedFrom " sind mögliche Ereignisauslöser, die geeignete Positionen in der Zustandsverwaltung und objektlebensdauer aufweisen, sodass Sie sie zum Entfernen von Handlern für andere Ereignisse verwenden können.

Beispielsweise können Sie mithilfe dieses Codes einen Ereignishandler namens textBlock1_PointerEntered aus dem Zielobjekt "textBlock1 " entfernen.

textBlock1.PointerEntered -= textBlock1_PointerEntered;

Sie können auch Handler für Fälle entfernen, in denen das Ereignis über ein XAML-Attribut hinzugefügt wurde, was bedeutet, dass der Handler im generierten Code hinzugefügt wurde. Dies ist einfacher, wenn Sie einen Name-Wert für das Element angegeben haben, an das der Handler angefügt wurde, da dies später einen Objektverweis für Code bereitstellt. Sie können jedoch auch die Objektstruktur durchlaufen, um den erforderlichen Objektverweis in Fällen zu finden, in denen das Objekt keinen Namen hat.

Wenn Sie einen Ereignishandler in C++/CX entfernen müssen, benötigen Sie ein Registrierungstoken, das Sie vom Rückgabewert der += Ereignishandlerregistrierung erhalten haben sollten. Der Grund dafür ist, dass der Wert, den Sie für die rechte Seite der -= Deregistrierung in der C++/CX-Syntax verwenden, das Token und nicht der Methodenname ist. Für C++/CX können Sie keine Handler entfernen, die als XAML-Attribut hinzugefügt wurden, da der generierte C++/CX-Code kein Token speichert.

Geroutete Ereignisse

Die Windows-Runtime unterstützt das Konzept eines Routingereignisses für eine Reihe von Ereignissen, die in den meisten UI-Elementen vorhanden sind. Diese Ereignisse gelten für Eingabe- und Benutzerinteraktionsszenarien und werden in der UIElement-Basisklasse implementiert. Hier ist eine Liste der Eingabeereignisse, die Routingereignisse sind:

Ein Routingereignis ist ein Ereignis, das potenziell von einem untergeordneten Objekt an jedes seiner aufeinander folgenden übergeordneten Objekte in einer Objektstruktur übergeben wird (weitergeleitet). Die XAML-Struktur Ihrer Benutzeroberfläche ähnelt diesem Baum, wobei die Wurzel dieses Baums das Wurzelelement in XAML ist. Die tatsächliche Objektstruktur kann sich von der XAML-Elementschachtelung unterscheiden, da die Objektstruktur keine XAML-Sprachfeatures wie Eigenschaftenelementtags enthält. Routingereignisse durchlaufen die Struktur nach dem Bubblingkonzept von untergeordneten XAML-Objektelementen, die das Ereignis auslösen, zu den übergeordneten Objekten, in denen sie enthalten sind. Das Ereignis und die zugehörigen Ereignisdaten können auf mehreren Objekten entlang der Ereignisroute behandelt werden. Wenn kein Element über Handler verfügt, wird die Route möglicherweise bis zum Erreichen des Stammelements fortgesetzt.

Wenn Sie Webtechnologien wie Dynamic HTML (DHTML) oder HTML5 kennen, sind Sie möglicherweise bereits mit dem Bubbling-Ereigniskonzept vertraut.

Wenn für ein Routingereignis ein Bubbling durch die zugehörige Ereignisroute erfolgt, greifen alle angefügten Ereignishandler auf eine freigegebene Instanz von Ereignisdaten zu. Wenn eines der Ereignisdaten von einem Handler geschrieben werden kann, werden daher alle änderungen, die an Ereignisdaten vorgenommen wurden, an den nächsten Handler übergeben und stellen möglicherweise nicht mehr die ursprünglichen Ereignisdaten aus dem Ereignis dar. Wenn ein Ereignis ein Routingereignisverhalten aufweist, enthält die Referenzdokumentation Hinweise oder andere Notationen zum Routingverhalten.

Die OriginalSource-Eigenschaft von RoutedEventArgs

Wenn ein Ereignis eine Ereignisroute aufbläht, ist der Absender nicht mehr dasselbe Objekt wie das Ereignis auslösende Objekt. Der Absender ist stattdessen das Objekt, an das der aufgerufene Handler angefügt ist.

In einigen Fällen interessieren Sie sich nicht für das sender-Objekt, sondern eher dafür, auf welchem der möglichen untergeordneten Objekte sich der Mauszeiger beim Auslösen eines Zeigerereignisses befindet oder welches Objekt in einer größeren UI beim Drücken einer Taste den Fokus hatte. In diesen Fällen können Sie den Wert der OriginalSource-Eigenschaft verwenden. An allen Punkten auf der Route meldet OriginalSource das ursprüngliche Objekt, das das Ereignis ausgelöst hat, anstelle des Objekts, an dem der Handler angefügt ist. Bei UIElement-Eingabeereignissen ist dieses ursprüngliche Objekt jedoch häufig ein Objekt, das im XAML-Code der UI-Definition auf Seitenebene nicht sofort sichtbar ist. Stattdessen kann es sich bei diesem ursprünglichen Quellobjekt um einen vorlagenbasierten Teil eines Steuerelements handeln. Wenn der Benutzer beispielsweise den Mauszeiger über den Rand einer Schaltfläche bewegt, handelt es sich bei den meisten Zeigerereignissen bei der OriginalSource um einen Rahmenvorlagenteil in der Vorlage, nicht um die Schaltfläche selbst.

Tipp: Das Bubbling von Eingabeereignissen ist besonders nützlich, wenn Sie ein Steuerelement mit Vorlagen erstellen. Jedes Steuerelement, das über eine Vorlage verfügt, kann von seinem Benutzer eine neue Vorlage angewendet bekommen. Der Verbraucher, der versucht, eine Arbeitsvorlage neu zu erstellen, kann unbeabsichtigt eine ereignisbasierte Behandlung beseitigen, die in der Standardvorlage deklariert ist. Sie können dennoch eine Ereignisbehandlung auf Steuerelementebene bereitstellen, indem Sie Handler als Teil OnApplyTemplate-Überschreibung in der Klassendefinition anfügen. Anschließend können Sie die Eingabeereignisse abfangen, die bei der Instanziierung per Bubbling zum Stamm des Steuerelements weitergeleitet werden.

Die Handled-Eigenschaft

Mehrere Ereignisdatenklassen für bestimmte Routingereignisse enthalten eine Eigenschaft namens Handled. Beispiele finden Sie unter PointerRoutedEventArgs.Handled, KeyRoutedEventArgs.Handled, DragEventArgs.Handled. In allen Fällen ist Handled eine settable boolean-Eigenschaft.

Das Festlegen der Handled-Eigenschaft auf "true " wirkt sich auf das Ereignissystemverhalten aus. Wenn Handled auf wahr gesetzt ist, wird das Routing für die meisten Ereignishandler gestoppt; das Ereignis setzt seinen Weg nicht weiter fort, um andere angefügte Handler über diesen spezifischen Ereignisfall zu informieren. Was "behandelt" im Kontext des Ereignisses bedeutet und wie Ihre App darauf reagiert, liegt bei Ihnen. Im Grunde ist Handled ein einfaches Protokoll, mit dem im App-Code angegeben werden kann, dass das Auftreten eines Ereignisses nicht per Bubbling an Container weitergeleitet werden muss, da Ihre App-Logik sich um die notwendigen Schritte gekümmert hat. Umgekehrt müssen Sie jedoch darauf achten, dass Sie keine Ereignisse behandeln, die wahrscheinlich ein Bubbling ausführen sollten, damit integrierte System- oder Steuerungsverhalten reagieren können. Beispielsweise kann die Behandlung von Ereignissen auf niedriger Ebene in den Teilen oder Elementen eines Auswahlsteuerelements nachteilig sein. Das Auswahlsteuerelement sucht möglicherweise nach Eingabeereignissen, um festzustellen, ob die Auswahl geändert werden muss.

Nicht alle Routingereignisse können eine Route auf diese Weise abbrechen, und Sie können feststellen, dass sie nicht über eine Handled-Eigenschaft verfügen. Beispielsweise führen GotFocus and LostFocus Bubbling aus. Sie führen dieses Bubbling jedoch stets bis zum Stamm aus, und ihre Ereignisdatenklassen besitzen die Eigenschaft Handled nicht, die dieses Verhalten beeinflussen kann.

Eingabeereignishandler in Steuerelementen

Bestimmte Windows-Runtime-Steuerelemente verwenden manchmal das Konzept " Handled " für Eingabeereignisse intern. Dies kann dazu führen, dass ein Eingabeereignis nie auftritt, da der Benutzercode es nicht verarbeiten kann. Beispielsweise enthält die Button-Klasse Logik, die das allgemeine Eingabeereignis PointerPressed bewusst behandelt. Dies geschieht, da Schaltflächen ein Click-Ereignis auslösen, das von Zeigereingaben initiiert wird, sowie von anderen Eingabemodi, z. B. die Behandlung von Tasten wie der EINGABETASTE, die die Schaltfläche aufrufen kann, wenn sie fokussiert ist. Für den Klassenentwurf von Button wird das unformatierte Eingabeereignis konzeptionell behandelt, und Klassenverbraucher wie Ihr Benutzercode können stattdessen mit dem steuerelementrelevanten Click-Ereignis interagieren. Themen für bestimmte Steuerelementklassen in der Windows-Runtime-API-Referenz beachten häufig das Ereignisbehandlungsverhalten, das von der Klasse implementiert wird. In einigen Fällen können Sie das Verhalten ändern, indem Sie OnEvent-Methoden außer Kraft setzen. Sie können z. B. ändern, wie Ihre von TextBox abgeleitete Klasse auf die Eingabe von Schlüsseln reagiert, indem Sie Control.OnKeyDown überschreiben.

Registrieren von Handlern für bereits behandelte Routingereignisse

Weiter oben haben wir gesagt, dass das Festlegen von Handled auf "true " verhindert, dass die meisten Handler aufgerufen werden. Die AddHandler-Methode bietet jedoch eine Methode, mit der Sie einen Handler anfügen können, der immer für die Route aufgerufen wird, auch wenn ein anderer Handler weiter oben in der Route "Handled " in den freigegebenen Ereignisdaten auf "true " festgelegt hat. Diese Technik ist nützlich, wenn ein von Ihnen verwendetes Steuerelement das Ereignis in seiner inneren Zusammensetzung behandelt hat. Sie eignet sich auch für spezielle Steuerelementlogik, Allerdings möchten Sie trotzdem darauf aus einer Steuerungseinheit oder der Benutzeroberfläche Ihrer App reagieren. Verwenden Sie diese Technik jedoch mit Vorsicht, da sie dem Zweck von Handled widersprechen und möglicherweise die beabsichtigten Interaktionen eines Steuerelements unterbrechen kann.

Nur die Routingereignisse mit einem entsprechenden Routingereignisbezeichner können das AddHandler-Ereignisbehandlungsverfahren verwenden, da der Bezeichner eine erforderliche Eingabe der AddHandler-Methode ist. In der Referenzdokumentation für AddHandler finden Sie eine Liste von Ereignissen, für die Routingereignisbezeichner verfügbar sind. In den meisten Fällen ist dies die gleiche Liste mit Routingereignissen, die wir Ihnen zuvor gezeigt haben. Die Ausnahme besteht darin, dass die beiden letzten in der Liste: GotFocus und LostFocus keinen Routingereignisbezeichner haben, sodass Sie AddHandler für diese nicht verwenden können.

Geroutete Ereignisse außerhalb des visuellen Baums

Bestimmte Objekte sind Bestandteil einer Beziehung mit der primären visuellen Struktur. Diese ist konzeptionell, wie z. B. eine Überlagerung über die visuellen Hauptobjekte. Diese bestimmten Objekte gehören nicht zu den üblichen Beziehungen zwischen übergeordneten und untergeordneten Elementen, mit denen alle Strukturelemente mit dem visuellen Stamm verbunden sind. Dies ist der Fall für alle angezeigten Popups oder QuickInfos. Wenn Sie Routingereignisse aus einem Popup oder QuickInfo behandeln möchten, platzieren Sie die Handler in bestimmten UI-Elementen, die sich in der Popup- oder QuickInfo befinden, und nicht auf die Popup - oder QuickInfo-Elemente selbst. Verlassen Sie sich nicht auf das Routing innerhalb eines Compositings, das für Popup- oder ToolTip-Inhalte ausgeführt wird. Das Ereignisrouting für geroutete Ereignisse funktioniert nur entlang der visuellen Hauptstruktur. Ein Popup- oder ToolTip-Element wird nicht als übergeordnetes Element untergeordneter UI-Elemente betrachtet und empfängt das Routingereignis in keinem Fall, auch wenn es versucht, Elemente wie den Popup-Standardhintergrund als Erfassungsbereich für Eingabeereignisse zu verwenden.

Treffertests und Eingabeereignisse

Das Bestimmen, ob und wo ein Element in der Benutzeroberfläche von Maus-, Touch- und Stifteingaben erkannt wird, wird als Treffererkennung bezeichnet. Bei Toucheingabeaktionen und interaktionsspezifischen Ereignissen oder Manipulationsereignissen, die aus einer Toucheingabeaktion resultieren, muss ein Element bei Treffertests sichtbar sein, damit es der Ereignisquelle entsprechen und das der Aktion zugeordnete Ereignis auslösen kann. Andernfalls gelangt die Aktion durch das Element zu allen zugrunde liegenden oder übergeordneten Elementen im visuellen Baum, die mit dieser Eingabe interagieren können. Es gibt mehrere Faktoren, die sich auf Treffertests auswirken, aber Sie können bestimmen, ob ein bestimmtes Element Eingabeereignisse auslösen kann, indem Sie seine IsHitTestVisible-Eigenschaft überprüfen. Diese Eigenschaft gibt " true" nur zurück, wenn das Element diese Kriterien erfüllt:

  • Der Visibility-Eigenschaftswert des Elements ist Visible.
  • Der Wert der Background - oder Fill-Eigenschaft des Elements ist nicht NULL. Der Wert null für Brush führt zu Transparenz und Unsichtbarkeit von Treffertests. (Um ein Element transparent zu machen, aber auch treffertestbar zu machen, verwenden Sie einen transparenten Pinsel anstelle von NULL.)

Hinweis: Background und Fill sind nicht durch UIElement definiert, sondern durch verschiedene abgeleitete Klassen wie Control und Shape. Die Auswirkungen von Pinsel, die Sie für Vordergrund- und Hintergrundeigenschaften verwenden, sind jedoch für Treffertests und Eingabeereignisse identisch, unabhängig davon, welche Unterklasse die Eigenschaften implementiert.

  • Wenn es sich bei dem Element um ein Steuerelement handelt, muss der Wert der IsEnabled-Eigenschaft"true" sein.
  • Das Element muss tatsächliche Abmessungen im Layout aufweisen. Ein Element, bei dem entweder ActualHeight und ActualWidth 0 sind, löst keine Eingabeereignisse aus.

Einige Steuerelemente verfügen über spezielle Regeln für Treffertests. Beispielsweise verfügt TextBlock über keine Background-Eigenschaft, ist aber dennoch innerhalb des gesamten Bereichs seiner Dimensionen auf Treffergenauigkeit prüfbar. Die Steuerelemente Image und MediaElement können in den zugehörigen definierten Rechtecksdimensionen auf Treffer getestet werden. Dabei ist es unerheblich, ob in der Medienquelldatei transparente Inhalte wie Alphakanäle angezeigt werden. WebView-Steuerelemente weisen ein spezielles Treffertestverhalten auf, da die Eingabe durch das gehostete HTML behandelt werden und Skriptereignisse auslösen kann.

Für die meisten Panel-Klassen und Border-Elemente können im eigenen Hintergrund zwar keine Treffertests ausgeführt werden, sie können jedoch dennoch Benutzereingabeereignisse verarbeiten, die von den in ihnen integrierten Elementen weitergeleitet werden.

Sie können bestimmen, welche Elemente sich an derselben Position wie ein Benutzereingabeereignis befinden, unabhängig davon, ob die Elemente treffertestbar sind. Rufen Sie dazu die FindElementsInHostCoordinates-Methode auf. Wie der Name nahe legt, findet diese Methode die Elemente an einer Position relativ zu einem angegebenen Hostelement. Allerdings können angewendete Transformationen und Layoutänderungen das relative Koordinatensystem eines Elements anpassen und sich daher darauf auswirken, welche Elemente an einer bestimmten Position gefunden werden.

Befehle

Eine kleine Anzahl von UI-Elementen unterstützt befehle. Befehle verwenden eingabebezogene Routingereignisse in der zugrunde liegenden Implementierung und ermöglichen die Verarbeitung verwandter UI-Eingaben (eine bestimmte Zeigeraktion, eine bestimmte Tastenkombination) durch Aufrufen eines einzelnen Befehlshandlers. Wenn die Befehle für ein UI-Element verfügbar sind, sollten Sie die Befehls-APIs anstelle einzelner Eingabeereignisse verwenden. In der Regel verwenden Sie einen Bindungsverweis in Eigenschaften einer Klasse, die das Ansichtsmodell für Daten definiert. Die Eigenschaften enthalten benannte Befehle, die das sprachspezifische ICommand-Befehlsmuster implementieren. Weitere Informationen finden Sie unter ButtonBase.Command.

Benutzerdefinierte Ereignisse in der Windows-Runtime

Zum Definieren von benutzerdefinierten Ereignissen hängt die Art des Hinzufügens des Ereignisses und dessen Bedeutung für das Klassendesign stark von der verwendeten Programmiersprache ab.

  • Für C# definieren Sie ein CLR-Ereignis. Sie können das standardmäßige .NET-Ereignismuster verwenden, solange Sie keine benutzerdefinierten Accessoren (hinzufügen/entfernen) verwenden. Weitere Tipps:
  • Informationen zu C++/CX finden Sie unter "Ereignisse (C++/CX)".
    • Verwenden Sie benannte Verweise auch für Ihre eigenen Nutzungen von benutzerdefinierten Ereignissen. Verwenden Sie lambda nicht für benutzerdefinierte Ereignisse, sie kann einen Zirkelverweis erstellen.

Sie können kein benutzerdefiniertes Routingereignis für Windows-Runtime deklarieren. Routingereignisse sind auf den Satz beschränkt, der von der Windows-Runtime stammt.

Das Definieren eines benutzerdefinierten Ereignisses erfolgt in der Regel als Teil der Übung zum Definieren eines benutzerdefinierten Steuerelements. Eine Abhängigkeitseigenschaft mit einem Rückruf für Eigenschaftsänderungen ist ein gängiges Muster, genau wie das Definieren eines benutzerdefinierten Ereignisses, das in manchen oder in allen Fällen durch den Abhängigkeitseigenschaftsrückruf ausgelöst wird. Benutzer Ihres Steuerelements haben keinen Zugriff auf den von Ihnen definierten Rückruf für Eigenschaftsänderungen; die beste Methode ist das Bereitstellen eines Benachrichtigungsereignisses. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften.