27.3 Der Ereignishandler
Lassen Sie uns jetzt einen Blick auf die Ereignishandler der Routed Events werfen. Im Grunde genommen unterscheiden sich die Parameter nicht von denen der klassischen CLR-Ereignisse: Im ersten Parameter gibt sich der Auslöser des Events bekannt, im zweiten werden ereignisspezifische Daten bereitgestellt. Während in CLR-Ereignissen der zweite Parameter immer vom Typ EventArgs ist, basiert der zweite Parameter eines Routed Events auf dem Typ RoutedEventArgs (der übrigens selbst von EventArgs abgeleitet ist).
Alle EventArgs-Parameter in der WPF sind von RoutedEventArgs abgeleitet. Im Code des letzten Beispiels handelt es sich dabei um ein Objekt vom Typ MouseButtonEventArgs. Dieser Typ ist über seine direkte Basis MouseEventArgs auf RoutedEventArgs zurückzuführen.
27.3.1 Die Klasse »RoutedEventArgs«
RoutedEventArgs liefert insgesamt vier interessante Informationen, die Sie Tabelle 27.1 entnehmen können.
Eigenschaft | Beschreibung |
Diese Eigenschaft ermöglicht es, den Routing-Prozess zu stoppen. Dazu ist Handled auf true zu setzen. Dadurch wird die Ereigniskette nicht nur unterbrochen, sondern beendet. |
|
RoutedEvent |
Diese Eigenschaft liefert die RoutedEvent-Instanz, die mit dem RoutedEventArgs-Objekt verbunden ist. |
Gibt das Element an, das für die Einleitung des Routing-Prozesses verantwortlich zeichnet. |
|
Liefert das Objekt aus dem Visual Tree, das ursächlich das Ereignis ausgelöst hat. |
Vermutlich wird Ihnen der Unterschied zwischen den beiden Eigenschaften Source und OriginalSource nicht sofort klar sein. Die Konfusion wird vermutlich perfekt, wenn außer diesen beiden Eigenschaften auch noch der erste Parameter (sender) des Ereignishandlers in unsere Betrachtung einbezogen wird. Worin unterscheiden sich sender, Source und OriginalSource?
27.3.2 Die Quelle des Routing-Prozesses
Am besten verständlich wird der Unterschied, wenn wir die Ausgabe des Beispiels Sample1 von oben entsprechend anpassen. Dabei ist es vollkommen ausreichend, wenn wir uns auf die gebubbelten Events beschränken.
// Beispiel: .. \Kapitel 27\RoutedEventSamples\Sample2
<Window ...
MouseRightButtonDown="MouseRight">
<StackPanel MouseRightButtonDown="MouseRight">
<Button MouseRightButtonDown="MouseRight">
<StackPanel MouseRightButtonDown="MouseRight">
<Image MouseRightButtonDown="MouseRight"/>
<Label MouseRightButtonDown="MouseRight">Abbrechen</Label>
</StackPanel>
</Button>
<ListBox x:Name="listBox1"></ListBox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Click="Button_Click">Liste löschen</Button>
</Grid>
</StackPanel>
</Window>
// Programmcode in der Code-Behind-Datei
private void MouseRight(object sender, MouseButtonEventArgs e) {
string message = "Sender: " + sender + "\n";
message += "Source: " + e.Source + "\n";
message += "OriginalSource: " + e.OriginalSource + "\n";
listBox1.Items.Add(message);
}
Listing 27.5 Demonstration der EventArgs-Parameter
Klicken wir auf das Label, werden die Resultate in der ListBox angezeigt. Der besseren Übersicht wegen sei die Ausgabe tabellarisch wiedergegeben.
Sender | Source | OriginalSource |
Label |
Label |
TextBlock |
StackPanel |
Label |
TextBlock |
Button |
Label |
TextBlock |
StackPanel |
Label |
TextBlock |
Window |
Label |
TextBlock |
Die Aussage, dass die gebubbelten Ereignisse ausgehend vom Label im Elementbaum nach oben bis zum Fenster weitergereicht werden, sehen wir in der Ausgabe des Parameters sender bestätigt. Der Parameter liefert die Komponente, die aktuell das Ereignis ausgelöst hat – obwohl der Verursacher der Ereigniskette eine ganz andere Komponente ist.
Die Eigenschaft Source beschreibt den tatsächlichen Auslöser des Routing-Prozesses: Hier ist es das Label. Allgemein gesprochen handelt es sich dabei um die Komponente, die sowohl im Virtual Tree als auch im Logical Tree zu finden ist.
Die Angabe OriginalSource geht ins Detail. Hierzu sei erklärend gesagt, dass jedes Steuerelement durch eine »Schablone« beschrieben wird, das sogenannte ControlTemplate. Die Komponente TextBlock ist innerhalb des ControlTemplates eines Labels die Komponente, die für die Ausgabe des Textes sorgt. Somit beschreibt die Eigenschaft OriginalSource das Element aus dem Visual Tree, das im Hintergrund tatsächlich für die Eventauslösung verantwortlich ist.
27.3.3 Die Eigenschaft »Handled«
Innerhalb eines Ereignishandlers kann die Eigenschaft Handled dazu verwendet werden, ein Ereignis als »behandelt« zu markieren. Dazu wird Handled=true gesetzt. Die Folge ist, dass die Aufrufe aller weiteren Ereignishandler, die auf der Route des Ereignisses liegen, unterdrückt werden. Dies lässt sich sehr schnell anhand des Beispiels Sample2 überprüfen.
private void MouseRight(object sender, MouseButtonEventArgs e) {
string message = "Sender: " + sender + "\n";
message += "Source: " + e.Source + "\n";
message += "OriginalSource: " + e.OriginalSource + "\n";
listBox1.Items.Add(message);
if (sender is Button) e.Handled = true;
}
Listing 27.6 Ergänzung des Ereignishandlers aus dem Beispiel »Sample2«
Das »äußere« StackPanel und das Window werden den Ereignishandler nicht mehr aufrufen.
Auch wenn Handled auf true gesetzt ist, durchläuft das System weiterhin die komplette Route. Tatsächlich gibt es sogar die Möglichkeit, einen Ereignishandler ausführen zu lassen, wenn vorher das Ereignis bereits mit Handled=true für behandelt erklärt wird. Wie das gemacht wird, sehen Sie am Beispiel des Buttons in Abschnitt 27.4.3.
27.3.4 Registrieren und Deregistrieren eines Ereignishandlers mit Code
Zur Installation des Ereignishandlers eines Routed Events stehen Ihnen zwei Möglichkeiten zur Verfügung. Sie können einerseits mit »+=« in bekannter Weise das Ereignis mit einem Ereignishandler verbinden, z. B.:
button1.Click += new RoutedEventHandler(button1_Click);
Die zweite Variante stellt die Methode AddHandler dar, die von den Klassen UIElement, UIElement3D und ContentElement bereitgestellt wird und auf das von diesen Klassen implementierte Interface IInputElement zurückzuführen ist.
button1.AddHandler(Button.ClickEvent, new RoutedEventHandler(button1_Click))
Das Deregistrieren eines Event Handlers erfolgt ähnlich. Entweder Sie benutzen -=, also z. B.
button1.Click -= new RoutedEventHandler(button1_Click);
oder die Methode RemoveHandler:
button1.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(button1_Click))
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.