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.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.