Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 27 Ereignisse in der WPF
Pfeil 27.1 Ereignishandler bereitstellen
Pfeil 27.2 Routing-Strategien
Pfeil 27.2.1 Der durchlaufene Elementbaum
Pfeil 27.2.2 Beispielanwendung
Pfeil 27.2.3 Sonderfall der Mausereignisse
Pfeil 27.3 Der Ereignishandler
Pfeil 27.3.1 Die Klasse »RoutedEventArgs«
Pfeil 27.3.2 Die Quelle des Routing-Prozesses
Pfeil 27.3.3 Die Eigenschaft »Handled«
Pfeil 27.3.4 Registrieren und Deregistrieren eines Ereignishandlers mit Code
Pfeil 27.4 Definition eines Routed Events
Pfeil 27.4.1 Ereignisauslösung
Pfeil 27.4.2 Das Ereignis als Attached Event verwenden
Pfeil 27.4.3 Unterdrückte Ereignisse
Pfeil 27.5 Mausereignisse in der WPF
Pfeil 27.5.1 Ziehen der Maus
Pfeil 27.5.2 Auswerten der Mausklicks
Pfeil 27.5.3 Capturing

Galileo Computing - Zum Seitenanfang

27.4 Definition eines Routed EventsZur nächsten Überschrift

Routed Events können nur in Klassen implementiert werden, die von einer der folgenden Basen abgeleitet sind:

  • UIElement
  • UIElement3D
  • ContentElement

Hintergrund dessen ist, dass die Schnittstelle IInputElement implementiert sein muss, die unter anderen die Methoden AddHandler, RemoveHandler und RaiseEvent vorschreibt. Alle drei Methoden werden wir in diesem Abschnitt noch einsetzen.

Das Ereignismodell der Routed Events ähnelt dem der Dependency Properties. Ein Routed Event wird ebenfalls durch ein static readonly-Feld beschrieben, das beim WPF-Subsystem registriert werden muss. Der Typ ist dabei immer RoutedEvent. Per Konvention wird dem Bezeichner das Suffix Event angehängt.

In diesem Abschnitt möchte ich Ihnen zeigen, wie ein Routed Event bereitgestellt wird. Damit alles nicht schwieriger wird als notwendig, wird dazu die Klasse Button aus dem Namespace System.Windows.Controls abgeleitet und um das Ereignis SayHello erweitert. Sie finden das komplette Beispiel auf der Buch-DVD unter \Kapitel 27\RoutedEventSamples\Sample3.

public class SpecializedButton : Button {
public static readonly RoutedEvent SayHelloEvent;
}

Listing 27.7 Definition des Events »SayHello«

Für die Registrierung eignet sich auch in diesem Fall der statische Konstruktor. Die Registrierung erfolgt mit der statischen Methode RegisterRoutedEvent der Klasse EventManager. Der erste Parameter der Methode erwartet den Namen des Events. Das zweite Argument beschreibt die verfolgte Routing-Strategie und kann auf Direct, Bubble oder Tunnel eingestellt werden. Dem dritten Parameter wird der Typ des Delegaten mitgeteilt, und der vierte Parameter beschreibt den Typ der Klasse, in dem der Event definiert ist.

static SpezializedButton() {
SayHalloEvent = EventManager.RegisterRoutedEvent("SayHello",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(SpezializedButton));
}

Listing 27.8 Registrierung des Routed Events im statischen Konstruktor

Zum Schluss muss nur noch je ein Accessor zum Hinzufügen und Entfernen eines Ereignishandlers geschrieben werden, denn ansonsten wäre einerseits die klassische Verbindung eines Ereignisses mit einem Ereignishandler mit »+=« nicht möglich, andererseits ließe sich ein Routed Event auch nicht im XAML-Code benutzen. Auch das erinnert wieder stark an die Dependency Properties mit ihrem get-/set-Wrapper.

public event RoutedEventHandler SayHello {

add {
AddHandler(SpezializedButton.SayHelloEvent, value);
}

remove {
RemoveHandler(SpezializedButton.SayHelloEvent, value);
}
}

Listing 27.9 Bereitstellung der Accessoren

Die Signatur sieht aus wie die Definition eines gewöhnlichen CLR-Ereignisses. Der Event-Wrapper beherbergt die beiden Accessoren add und remove. Bei value handelt es sich, genauso wie bei einem set-Accessor, um einen impliziten Parameter, der den Delegaten beschreibt, der entweder hinzugefügt oder entfernt werden soll. Die beiden Methoden AddHandler und RemoveHandler stammen aus dem Interface IInputElement.

Ein direkter Event verhält sich in gleicher Weise wie ein klassischer CLR-Event. Er wird in einer Komponente ausgelöst und kann nicht von umgebenden Komponenten verarbeitet werden. Betrachten wir die Methode RegisterRoutedEvent der Klasse Eventmanager, stellen wir fest, dass uns auch die Option RoutingStrategy.Direct angeboten wird. Damit stellt sich die Frage, ob wir ein direktes Ereignis klassisch bereitstellen oder uns für die Registrierung beim EventManager entscheiden sollten.

Die Antwort ist eindeutig: Sie sollten sich für die zweite Variante entscheiden, also auch direkte Events beim EventManager registrieren. Der Grund dafür ist in verschiedenen Fähigkeiten der WPF zu finden, die voraussetzen, dass ein direkter Event als Routed Event implementiert ist. Dazu gehört beispielsweise die Fähigkeit von XAML, mit EventTriggern auf Ereignisse zu reagieren.


Galileo Computing - Zum Seitenanfang

27.4.1 EreignisauslösungZur nächsten ÜberschriftZur vorigen Überschrift

So weit vorbereitet muss ein Event nur noch ausgelöst werden. Wann das genau passiert, ist eine Entscheidung, die der Entwickler treffen muss. Die Methode, in der das Ereignis ausgelöst wird, kann jede beliebige sein.

Das Feuern eines Routed Events unterscheidet sich von dem eines klassischen CLR-Events. Dem EventArgs-Parameter werden zuerst alle erforderlichen Informationen übergeben. Anschließend wird ein Routed Event, im Gegensatz zu den CLR-Ereignissen, mit der Methode RaiseEvent ausgelöst. Angenommen, wir wollen das Ereignis SayHello der SpecializedButton-Instanz in einer Methode namens DoSomething auslösen, könnte der Code wie folgt aussehen:

public void DoSomething() {
RoutedEventArgs e = new RoutedEventArgs();
e.RoutedEvent = SayHalloEvent;
e.Source = this;
RaiseEvent(e);
}

Listing 27.10 Auslösen des Ereignisses »SayHello«

Vielleicht stellen Sie sich beim ersten Betrachten des Codes die Frage, wo die Information über den Typ des auszulösenden Events zu finden ist. Es ist die Eigenschaft RoutedEvent, die die Instanz des auszulösenden Events beschreibt. Somit nimmt das RoutedEventArgs-Objekt eine zentrale Position innerhalb der WPF ein, anders als das herkömmliche EventArgs-Objekt außerhalb der WPF. Im Codefragment wird der einfache Einsatz des RoutedEventArgs-Parameters gezeigt, der bis auf die in Tabelle 27.1 aufgeführten Eigenschaften keine ereignisspezifischen Daten bereitstellt. Der Parameter kann natürlich auch durch ein spezifisches RoutedEventArgs-Objekt beschrieben werden, in dem ereignisspezifische Daten an den registrierten Ereignishandler gesendet werden. In einem solchen Fall müssen Sie eine separate Klasse codieren, die von RoutedEventArgs abgeleitet ist und das EventArgs-Objekt mit den gewünschten Daten vor dem Auslösen des Ereignisses versorgt.

Um das Ereignis SayHello zu Testzwecken auslösen zu können, wird in der Klasse SpecializedButton die geerbte Methode OnClick in der Weise überschrieben, dass in ihr unser Event SayHello ausgelöst wird, also:

protected override void OnClick() {
DoSomething();
}

Man könnte also sagen, dass wir damit Click durch SayHello ersetzen.


Galileo Computing - Zum Seitenanfang

27.4.2 Das Ereignis als Attached Event verwendenZur nächsten ÜberschriftZur vorigen Überschrift

Steuerelemente, die beispielsweise von UIElement abgeleitet sind, weisen von Anfang an zahlreiche Events auf, die als Routed Events definiert sind. Dazu gehören auch die von uns zu Beginn dieses Kapitels benutzten Ereignisse PreviewMouseLeftButtonDown und MouseLeftButtonDown. Jede Komponente innerhalb eines Elementbaums kann sich somit bei einem getunnelten oder gebubbelten Event direkt anmelden, weil es über diese Ereignisse verfügt.

Etwas anders ist der Sachverhalt, wenn wir in einer Komponente ein typspezifisches Ereignis einführen, wie beispielsweise den Event SayHello unserer Klasse SpecializedButton. Obwohl als Routed Event geprägt, genauer als gebubbelter Event, verfügt eine umgebende Komponente wie beispielsweise ein Grid nicht über das Ereignis SayHello.

Damit auch solche Ereignisse den Elementbaum durchlaufen können, definiert XAML die Attached-Event-Syntax. Damit lassen sich Ereignishandler für diesen Event auch in einer umgebenden Komponente installieren. Die allgemeine Syntax dazu sieht wie folgt aus:

[Typ].[Event] = "[Ereignishandler]"

Ist ein Objekt vom Typ SpecializedButton innerhalb einer Grid-Zelle positioniert, kann das Grid mit dem gebubbelten Ereignis wie im folgenden Code gezeigt verknüpft werden.

<Window ...
xmlns:local="clr-namespace:Sample3">
<Grid local:SpecializedButton.SayHello="Grid_SayHello">
<local:SpecializedButton x:Name="button1" SayHello="button1_SayHello">
SpecializedButton
</local:SpecializedButton>
</Grid>
</Window>

Listing 27.11 Typspezifische Bubbled Events im übergeordneten Element auslösen

Natürlich kann das Ereignis SayHello auf gleiche Weise auch im Window ausgelöst werden.


Galileo Computing - Zum Seitenanfang

27.4.3 Unterdrückte EreignisseZur vorigen Überschrift

Zum Abschluss unserer allgemeinen Betrachtungen der Routed Events bin ich Ihnen noch eine Erklärung schuldig. In Abschnitt 27.2.3 habe ich erwähnt, dass das Beispiel Sample1 nicht wie erwartet reagiert, wenn wir anstatt des gebubbelten Ereignisses MouseRightButtonDown das Ereignis MouseLeftButtonDown oder MouseDown behandeln. Die Ereigniskette wird abgebrochen und nicht bis zum Wurzelelement Window durchgesetzt.

Hintergrund dieser Verhaltensweise ist, dass in der Methode OnMouseLeftButtonDown das Ereignis als behandelt gekennzeichnet wird und das Click-Ereignis ausgelöst wird.

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
base.OnMouseLeftButtonDown(e);
e.Handled = true;
OnClick();
}

Listing 27.12 Ursache des Abbruchs der Ereigniskette der Events »MouseLeftButtonDown«

Um zu erzwingen, dass dennoch alle registrierten Handler abgearbeitet werden, müssen Sie den Handler des Controls, das für den Abbruch der Ereigniskette verantwortlich ist, neu registrieren. Dazu benutzt man eine Überladung der Methode AddHandler.

Um das zu demonstrieren, bietet sich das Beispielprogramm Sample1 an, das wir in Abschnitt 27.2.2 besprochen haben. Allerdings werden dort die beiden verwendeten Ereignisse PreviewMouseRightButtonDown und MouseRightButtonDown gegen die Entsprechungen, die die linke Maustaste behandeln, ersetzt.

Nun wollen wir die durch das Ereignis Click unterbrochene Ereigniskette vollständig durchlaufen. Dazu ist eine Neuregistrierung des Ereignisses MouseLeftButtonDown erforderlich:

public MainWindow() {
InitializeComponent();
button1.AddHandler(MouseLeftButtonDownEvent,
new MouseButtonEventHandler(MouseLeft),
true);
}

Listing 27.13 Neuregistrierung des Ereignishandlers für »MouseLeftButtonDown«

Geben Sie im ersten Argument den Routed Event an, der registriert werden soll, im zweiten Argument den Delegattyp des Ereignishandlers. Dem dritten Parameter muss true übergeben werden. Den Aufruf der Methode AddHandler positionieren Sie am besten wie gezeigt im Konstruktor des Window nach dem Aufruf von InitializeComponent.

Jetzt fehlt nur noch eine Ergänzung. Im Ereignishandler setzen Sie die e.Handled =true.

private void MouseLeft(object sender, MouseButtonEventArgs e) {

// Anweisungen

e.Handled = false;
}

Listing 27.14 Ergänzung im Ereignishandler

Sie finden das Beispiel auf der Buch-DVD unter \Kapitel 27\RoutedEventSamples\Sample4.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2012

Visual C# 2012
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de