Bubbling und Tunneling: Routed Events

Wenn Sie ein Abonnement des Magazins 'DATENBANKENTWICKLER' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.

Bubbling und Tunneling: Routed Events

Im Vergleich zu VBA, wo jedes Ereignis für das Steuer­element behandelt wurde, welches es auch ausgelöst hat, gibt es unter WPF einige Erweiterungen. Es gibt dort auch solche Ereignisse, aber in vielen Fällen werden Ereignisse an übergeordnete Elemente weitergeleitet. Das hört sich erstmal so an, als ob man es nicht unbedingt benötigt. Dennoch wollen wir das Prinzip anhand eines Beispiels erläutern, damit Sie mitunter auftretendes unerwartetes Verhalten von Code interpretieren können.

Unter WPF sind Elemente verschachtelt, das heißt, es gibt übergeordnete und untergeordnete Elemente. Das Window-Element ist normalerweise das Hauptelement, welches dann ein Grid enthält, in dem sich wiederum ein Stackpanel mit einer Schaltfläche befinden könnte:

<Window x:Class="BubblingAndTunneling.MainWindow" ... Title="MainWindow" Height="350" Width="525">
     <Grid>
         <StackPanel>
             <Button x:Name="btn" Content="Klick mich!" ... Click="btn_Click"></Button>
         </StackPanel>
     </Grid>
</Window>

Direkte Ereignisse/Direct Events

Wenn der Benutzer nun auf die Schaltfläche namens btn klickt, wird das Ereignis Click ausgelöst, welches üblicherweise durch eine Ereignismethode etwa namens btn_Click implementiert wird:

private void btn_Click(object sender, RoutedEventArgs e) {
     MessageBox.Show("Klick!");
}

Bei dem Click-Ereignis handelt es sich um ein direktes Ereignis. Dieses wird nur von dem Element ausgelöst, für das es implementiert wurde.

Tunneling Events

Bei Tunneling Events handelt es sich um alle Ereignisse, die mit dem Präfix Preview beginnen, also beispielsweise Preview­MouseDown. Was ist die Besonderheit dieser Ereignisse? Sie werden immer vom Element der obersten Ebene aus zu den unteren Ebenen abgearbeitet. Wenn Sie also das Ereignis PreviewMouseDown für alle vier Elemente des obigen Beispiels definieren, sieht das wie folgt aus:

<Window x:Class="BubblingAndTunneling.MainWindow" ... Title="MainWindow" Height="350" Width="525" MouseDown="Window_MouseDown" PreviewMouseDown="Window_PreviewMouseDown">
     <Grid MouseDown="Grid_MouseDown" PreviewMouseDown="Grid_PreviewMouseDown" >
         <StackPanel MouseDown="StackPanel_MouseDown" PreviewMouseDown="StackPanel_PreviewMouseDown">
             <Button x:Name="btn" Content="Klick mich!" ... MouseDown="btn_MouseDown" 
                 PreviewMouseDown="btn_PreviewMouseDown"></Button>
         </StackPanel>
     </Grid>
</Window>

Für diese Ereignisse hinterlegen wir die folgenden Methoden (für Debug.WriteLine müssen Sie den passenden Namespace mit using System.Diagnostics hinzufügen):

private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("Window_PreviewMouseDown");
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("Window_MouseDown");
}
private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("Grid_PreviewMouseDown");
}
private void Grid_MouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("Grid_MouseDown");                       
} 
private void StackPanel_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("StackPanel_PreviewMouseDown");
}
private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("StackPanel_MouseDown");
}
private void btn_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("btn_PreviewMouseDown");
}
private void btn_MouseDown(object sender, MouseButtonEventArgs e) {
     Debug.WriteLine("btn_MouseDown");
}

Wenn wir nun die Anwendung starten und mit der linken Maustaste auf die Schaltfläche klicken, erhalten wir das Ergebnis aus Bild 1. Es werden also offensichtlich nur die Tunneling-Methoden ausgelöst, also diejenigen, die mit Preview... beginnen.

Es feuert nur die Hälfte der angegebenen Ereignisse.

Bild 1: Es feuert nur die Hälfte der angegebenen Ereignisse.

Immerhin ist hier gut zu erkennen, dass dies ausgehend von der obersten Ebene (Window) bis runter zum Button-Element geschieht. Aber warum werden die MouseDown-Ereignisse nicht ausgelöst?

Dies ist wiederum der Fall, wenn wir auf den freien Bereich neben der Schaltfläche klicken. Dann erhalten wir die folgende Ausgabe:

Window_PreviewMouseDown
Grid_PreviewMouseDown
StackPanel_PreviewMouseDown
StackPanel_MouseDown
Grid_MouseDown
Window_MouseDown

Hier werden also korrekt erst die Tunneling-Ereignisse ausgelöst und dann in umgekehrte Reihenfolge die Bubbling-Ereignisse.

Bubbling Events

Bevor wir uns darum kümmern, warum beim Anklicken der Schaltfläche nur die Tunneling-Events ausgelöst werden, noch kurz die Erläuterung der Bubbling-Ereignisse. Dies sind die Ereignisse, die in umgekehrter Reihenfolge wie die Tunneling-Ereignisse ausgelöst werden – also ausgehend vom auslösenden Element bis hin zum obersten Element der Hierarchie (wie gut im Beispiel oben zu sehen, wo wir nicht die Schaltfläche, sondern das StackPanel-Element angeklickt haben). Diese werden allerdings immer nach den Tunneling-Ereignissen abgearbeitet.

Warum kein MouseDown?

Nun schauen wir uns an, warum die Bubbling Events nicht ausgeführt werden, wenn wir das Button-Element mit der linken Maustaste anklicken. Der Grund ist einfach: Wenn Sie mit der linken Maustaste auf einen Button klicken, wird dessen Click-Ereignis ausgelöst, was dafür sorgt, dass das MouseDown-Ereignis nicht mehr feuert – und somit auch nicht die MouseDown-Ereignisse der in der Hierarchie über dem Button-Element liegenden Elemente. Dies gilt beispielsweise auch für das Textfeld.

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Neues aus unseren Magazinen
Listenfeld: Reihenfolge mehrerer Einträge...

Wir haben bereits in mehreren Beiträgen beschrieben, wie Sie die individuelle Reihenfolge von Elementen einer Tabelle über den Inhalt eines Feldes etwa namens »ReihenfolgeID« einstellen können –... [mehr]

Diagramme mit gefilterten Daten

In Ausgabe 2/2019 haben wir in zwei Artikeln die modernen Diagramme von Access vorgestellt. Im vorliegenen Beitrag zeigen wir Ihnen, wie Sie diese abhängig von den in einem Formular angezeigten... [mehr]

Benutzerverwaltung mit verschlüsselten...

Wenn Sie in einer Access-Anwendung Benutzer verwalten wollen, die sich per Benutzername und Kennwort an die Anwendung anmelden, sollten Sie sehr sensibel mit den in der Anwendung gespeicherten... [mehr]

HTML-Tabellen mit fester Kopfzeile

In den vorherigen Ausgaben von Access im Unternehmen und in der aktuellen Ausgabe arbeiten wir in einigen Beiträgen mit dem Webbrowser-Steuerelement und stellen Daten, die wir mit den Bordmitteln... [mehr]

Flexible HTML-Tabellen mit fester Kopfzeile

Im Beitrag »HTML-Tabellen mit fester Kopfzeile« haben wir gezeigt, wie Sie Daten aus einer bestimmten Abfrage in einem Webbrowser-Steuerelement so anzeigen, dass die Spaltenköpfe oben fixiert... [mehr]

Berechtigungen per HTML verwalten

Im Beitrag »Benutzerverwaltung mit verschlüsselten Kennwörtern« stellen wir eine Lösung vor, in der wir die Berechtigungen von Benutzergruppen an Datenbankobjekten definieren. Dort benötigen wir... [mehr]

Benutzer und Berechtigungen ermitteln

In den Beiträgen »Benutzerverwaltung mit verschlüsselten Kennwörtern« und »Berechtigungen per HTML verwalten« haben wir die Voraussetzungen für eine Benutzerverwaltung geschaffen. Im vorliegenden... [mehr]

Zugriffsrechte mit Datenmakros

Es gibt verschiedene Möglichkeiten, auf Basis des aktuell angemeldeten Benutzers sicherzustellen, dass dieser nur die für ihn vorgesehenen Aktionen mit Daten durchführen darf – beispielsweise durch... [mehr]

Kennwörter generieren

Für den einen oder anderen Zweck möchten Sie vielleicht Kennwörter generieren oder in einer Benutzeroberfläche die Möglichkeit zum Generieren von Kennwörtern anbieten. Wenn Sie etwa Benutzer zu... [mehr]

Neuer Datensatz von Frontend zu Backend

Für manche Themen gibt es keine kurze, prägnante Überschrift. In diesem Fall wollen wir zeigen, wie Sie einen neuen Datensatz anlegen, der in einer temporären Tabelle im Frontend gespeichert wird,... [mehr]