27.5 Mausereignisse in der WPF
Bis hierher haben wir uns die WPF-typischen Routed Events im Detail angesehen und gelernt, wie sie innerhalb der Architektur der WPF arbeiten. Natürlich werden viele Ereignisse bereits von der WPF angeboten. Exemplarisch wollen wir daraus eine Gruppe herausgreifen, nämlich die Mausereignisse.
Es gibt zahlreiche Ereignisse, die im Zusammenhang mit einer Mausaktion ausgelöst werden: MouseLeftButtonDown, MouseRightButtonDown, MouseDoubleClick, MouseWheel usw. Die aufgeführten Events sind gebubbelte Events, zu denen sich auch noch die entsprechenden getunnelten gesellen.
27.5.1 Ziehen der Maus
Lassen Sie uns ein wenig über die Mausereignisse sprechen, die im Zusammenhang mit der Bewegung der Maus über eine Komponente stehen:
MouseEnter und MouseLeave sind direkte Ereignisse. Dabei wird MouseEnter ausgelöst, wenn der Mauszeiger in den Bereich einer Komponente eindringt, MouseLeave, wenn der Mauszeiger den Bereich der Komponente verlässt.
Im Gegensatz zu MouseEnter und MouseLeave hat die Bewegung des Mauszeigers über eine Komponente zwei Ereignisse zur Folge: PreviewMouseMove ist der getunnelte Event, MouseMove der gebubbelte.
Alle genannten Mausereignisse haben eines gemeinsam: Sie übergeben dem Ereignishandler ein MouseEventArgs-Objekt, das mit zahlreichen Informationen aufwartet. Die wichtigsten können Sie Tabelle 27.3 entnehmen.
Eigenschaft/Methode | Beschreibung |
Device |
Ruft das Eingabegerät ab (der Auslöser muss nicht zwangsläufig eine Maus sein, es kann sich auch um die Tastatur handeln oder einen Touchscreen). |
Handled |
Beschreibt einen booleschen Wert. Ist dieser auf true festgelegt, |
LeftButton MiddleButton RightButton |
Ruft den Zustand der entsprechenden Maustaste ab. |
Etwas ungewöhnlich für ein EventArgs-Objekt ist, dass mit GetPosition eine Methode bereitgestellt wird. Diese liefert uns die aktuellen Mauskoordinaten relativ zu dem Objekt, das der Methode als Argument übergeben wird. Der Rückgabewert der Methode ist eine Point-Instanz, die mit den Eigenschaften X und Y die Koordinatenwerte bezogen auf das im Argument genannte Objekt liefert.
Im folgenden Codeschnipsel wird gezeigt, wie die Koordinatenwerte bezogen auf das Window in der Titelleiste des Fensters angezeigt werden können, falls die linke Maustaste beim Ziehvorgang gedrückt ist. Der Koordinatenursprung einer grafischen Komponente ist dabei in der linken oberen Ecke der Bezugskomponente.
private void window_MouseMove(object sender, MouseEventArgs e) {
if (e.LeftButton == MouseButtonState.Pressed) {
Point pt = e.GetPosition(this);
Title = "X: " + pt.X + " | Y: " + pt.Y;
}
}
Listing 27.15 Anzeige der Positionskoordinaten in der Titelleiste
Die Eigenschaft LeftButton (und analog ebenfalls MiddleButton und RightButton) ist vom Typ der Enumeration MouseButtonState, die mit Released und Pressed nur zwei Mitglieder aufweist.
27.5.2 Auswerten der Mausklicks
Im Zusammenhang mit dem Klicken auf eine Maustaste haben Sie zahlreiche Möglichkeiten, darauf zu reagieren:
- PreviewMouseLeftButtonDown / MouseLeftButtonDown
- PreviewMouseRightButtonDown / MouseRightButtonDown
- PreviewMouseLeftButtonUp / MouseLeftButtonUp
- PreviewMouseRightButtonUp / MouseRightButtonUp
Andere WPF-Komponenten ergänzen die genannten Events noch um weitere Ereignisse. Beispielsweise stellt die Klasse Control darüber hinaus auch die Ereignisse PreviewMouseDoubleClick und MouseDoubleClick bereit.
Die Ereignisse, die im Zusammenhang mit dem Klicken stehen, stellen ein MouseButtonEventArgs-Objekt bereit. Die Klasse MouseButtonEventArgs ist von MouseEventArgs abgeleitet und ergänzt diese um weitere Member, die Sie der folgenden Tabelle entnehmen können.
Eigenschaft | Beschreibung |
Wertet den Zustand der Taste aus, die mit dem Event verknüpft ist. |
|
Ruft die Taste ab, die mit dem Event verknüpft ist. |
|
Ruft ab, wie oft die Taste gedrückt worden ist. Hier lässt sich zwischen einem Klick oder auch einem Doppelklick unterscheiden. |
Viele Entwickler stehen vor der Frage, ob sie bei Berücksichtigung von Mausereignissen ihren Code in das MouseDown- oder MouseUp-Ereignis codieren sollen. Die Antwort dazu lautet: In Windows-Anwendungen wird normalerweise immer auf die Up-Ereignisse reagiert.
27.5.3 Capturing
Normalerweise wird kurze Zeit nach dem Auslösen des MouseDown-Ereignisses auch das korrespondierende MouseUp-Ereignis ausgelöst. Es gibt aber durchaus Situationen, in denen das nicht der Fall ist. Stellen Sie sich einfach vor, Sie würden sich mit der Maus über einem Element befinden, die Maustaste drücken und dann die Maus im gedrückten Zustand aus der Komponente ziehen. Erfolgt das Loslassen der Maus außerhalb der Komponente, ist diese nicht mehr Empfänger des MouseUp-Events.
Soll die Komponente dennoch das MouseUp-Ereignis empfangen, müssen Maßnahmen ergriffen werden. Dazu stellt die WPF jeder von der Klasse UIElement abgeleiteten Komponente mehrere Möglichkeiten zur Verfügung, die Mausereignisse bei Bedarf zu fangen (engl.: capture) oder wieder freizugeben (engl.: release). Fängt eine Komponente die Maus, werden die Mausereignisse für diese Komponente ausgelöst, auch dann, wenn die Maus den Bereich der Komponente bereits verlassen hat. Erst wenn die Komponente die Maus wieder freigibt, ist das Ereignisverhalten wieder »normal«.
Es stehen mehrere Möglichkeiten zur Verfügung, die Maus zu fangen. Zum einen stellt die Klasse Mouse (Namespace System.Windows.Input) mit Capture eine Methode bereit, der als Argument die Komponente übergeben werden kann, die Besitz von der Maus ergreift. Zudem erben alle von UIElement abgeleiteten Klassen die Methode CaptureMouse und ReleaseMouseCapture und stellen darüber hinaus mit IsMouseCaptured und IsMouseCaptureWithin zwei Eigenschaften bereit, die Auskunft darüber erteilen, ob die Mausereignisse für die entsprechende Komponente ausgelöst werden. Neben den genannten Eigenschaften lösen die UIElement-Komponenten auch die Ereignisse GotMouseCapture, LostMouseCapture, IsMouseCaptureChanged und IsMouseCaptureWithinChanged aus.
Das Fangen eines Mausereignisses sehen wir uns an einem Beispiel an. Nehmen wir an, in einem Window werde ein Element vom Typ Ellipse in Beige dargestellt. Das Element soll auf die beiden Ereignisse MouseDown und MouseUp in der Weise reagieren, dass beim Drücken der Maus die Ellipse mit der Füllfarbe Blau angezeigt wird, beim Loslassen der Maus soll die ursprüngliche Farbe Beige wieder zu sehen sein.
// Beispiel: ..\Kapitel 27\CaptureSample
<Window ...>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Ellipse Fill="Beige" Grid.Row="0" Name="ellipse"
MouseDown="ellipse_MouseDown"
MouseUp="ellipse_MouseUp"></Ellipse>
</Grid>
</Window>
Listing 27.16 XAML-Code des Beispielprogramms »CaptureSample«
Im ersten Entwurf können die beiden Ereignishandler folgendermaßen implementiert werden:
private void ellipse_MouseDown(object sender, MouseButtonEventArgs e) {
Ellipse ellipse = (Ellipse)sender;
ellipse.Fill = Brushes.Blue;
}
private void ellipse_MouseUp(object sender, MouseButtonEventArgs e) {
Ellipse ellipse = (Ellipse)sender;
ellipse.Fill = Brushes.Beige;
}
Solange sich der Mauszeiger beim Klicken innerhalb des Bereichs der Ellipse befindet, schaltet ein Drücken der Maus die Füllfarbe auf Blau um und ein Loslassen zurück auf Beige. Halten Sie aber die Maustaste gedrückt, ziehen dann die Maus aus dem Bereich der Maus heraus und lassen erst dann die gedrückte Maustaste los, bleibt die Füllfarbe Blau erhalten.
Um das Problem mit einem Capturing der Maus zu lösen, müssen wir die Maus im Ereignishandler des MouseDown-Events mit der Methode CaptureMouse fangen. Die Methode liefert den Rückgabewert true, falls der Versuch gelingt. Falls das – aus welchen Gründen auch immer – nicht gelingt, darf die Füllfarbe auch nicht geändert werden. Daher ist der MouseDown-Ereignishandler wie folgt zu ändern:
private void ellipse_MouseDown(object sender, MouseButtonEventArgs e) {
Ellipse ellipse = (Ellipse)sender;
if (ellipse.CaptureMouse())
ellipse.Fill = Brushes.Blue;
}
Listing 27.17 Der Ereignishandler des »MouseDown«-Events
Jetzt gilt die Maus als gefangen, sie ist im Besitz des Ellipse-Elements. Das Programm funktioniert im ersten Moment wie gewünscht, allerdings gibt die Ellipse die Maus nicht frei. Das hat zur Konsequenz, dass weiterhin alle Mausklicks von der Ellipse empfangen werden – unabhängig davon, ob sich der Mauszeiger im Bereich der Ellipse befindet oder nicht. Zur Mausfreigabe muss zuerst überprüft werden, ob die Maus überhaupt im Besitz der Ellipse ist. Hier liefert die Eigenschaft IsMouseCaptured die notwendige Information. Die Freigabe selbst erfolgt durch Aufruf der Methode ReleaseMouseCapture.
private void ellipse_MouseUp(object sender, MouseButtonEventArgs e) {
Ellipse ellipse = (Ellipse)sender;
ellipse.Fill = Brushes.Beige;
if (ellipse.IsMouseCaptured)
ellipse.ReleaseMouseCapture();
}
Listing 27.18 Der Ereignishandler des »MouseUp«-Events
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.