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

Inhaltsverzeichnis
Vorwort zur 5. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Weitere .NET-Datentypen
7 Weitere Möglichkeiten von C#
8 Auflistungsklassen (Collections)
9 Fehlerbehandlung und Debugging
10 LINQ to Objects
11 Multithreading und die Task Parallel Library (TPL)
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 Einige wichtige .NET-Klassen
15 Projektmanagement und Visual Studio 2010
16 XML
17 WPF – Die Grundlagen
18 WPF-Containerelemente
19 WPF-Steuerelemente
20 Konzepte der WPF
21 Datenbindung
22 2D-Grafik
23 ADO.NET – verbindungsorientierte Objekte
24 ADO.NET – Das Command-Objekt
25 ADO.NET – Der SqlDataAdapter
26 ADO.NET – Daten im lokalen Speicher
27 ADO.NET – Aktualisieren der Datenbank
28 Stark typisierte DataSets
29 LINQ to SQL
30 Weitergabe von Anwendungen
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual C# 2010 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2010

Visual C# 2010
geb., mit DVD
1295 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1552-7
Pfeil 17 WPF – Die Grundlagen
Pfeil 17.1 Merkmale einer WPF-Anwendung
Pfeil 17.2 Anwendungstypen
Pfeil 17.3 Eine WPF-Anwendung und ihre Dateien
Pfeil 17.3.1 Die Datei »App.xaml«
Pfeil 17.3.2 Die Datei »App.xaml.cs«
Pfeil 17.3.3 Die Dateien ».baml« und ».g.cs«
Pfeil 17.4 Einführung in XAML
Pfeil 17.4.1 Struktur einer XAML-Datei
Pfeil 17.4.2 XAML-Elemente
Pfeil 17.4.3 Eigenschaften eines XAML-Elements festlegen
Pfeil 17.4.4 Typkonvertierung
Pfeil 17.4.5 Markup-Erweiterungen (Markup Extensions)
Pfeil 17.4.6 Namespaces
Pfeil 17.4.7 XAML-Spracherweiterungen
Pfeil 17.4.8 Markup-Erweiterungen
Pfeil 17.5 Abhängige und angehängte Eigenschaften
Pfeil 17.5.1 Abhängige Eigenschaften
Pfeil 17.5.2 Angehängte Eigenschaften
Pfeil 17.6 Logischer und visueller Elementbaum
Pfeil 17.6.1 Warum wird zwischen den Elementbäumen unterschieden?
Pfeil 17.6.2 Elementbäume mit Code ermitteln
Pfeil 17.7 Ereignisse in der WPF
Pfeil 17.7.1 Allgemeine Grundlagen
Pfeil 17.7.2 Routed Events


Galileo Computing - Zum Seitenanfang

17.7 Ereignisse in der WPF Zur nächsten ÜberschriftZur vorigen Überschrift


Galileo Computing - Zum Seitenanfang

17.7.1 Allgemeine Grundlagen Zur nächsten ÜberschriftZur vorigen Überschrift

Natürlich reagiert auch eine WPF-Anwendung nur dann, wenn Ereignisse ausgelöst werden. Zunächst einmal unterscheiden sich die Ereignisse nicht von den anderen im .NET Framework, das heißt, die Ereignishandler müssen zwei Parameter aufweisen: Der erste muss vom Typ Object sein, und der zweite muss von EventArgs abgeleitet sein.

Nehmen wir an, Sie möchten das Click-Ereignis einer Schaltfläche in der XAML-Datei programmieren. Sie können die IntelliSense-Unterstützung nutzen und daraus Click auswählen. Durch zweimaliges Drücken der Taste Tabulator -Taste wird im XAML-Code das Ereignis an einen Ereignishandler gebunden, der in der Code-Behind-Datei erzeugt wird.


<Grid>
  <Button Click="button1_Click"  Height="30" Name="button1" 
          Margin="70,95,133,0">Button1</Button>
</Grid>


Hinweis

Sie können einen Ereignishandler auch im Eigenschaftsfenster bereitstellen. Dazu schalten Sie die Ansicht der Eigenschaften in die Ansicht der Ereignisse um, indem Sie auf das Symbol mit dem Blitz klicken. Ein Doppelklick auf das gewünschte Ereignis genügt, um den Ereignishandler mit der üblichen Namenskonvention zu erzeugen.


Stellt eine Komponente ein Standardereignis bereit, können Sie den Ereignishandler auch mittels Doppelklick auf die Komponente bereitstellen. Das gilt zum Beispiel auch für den Button. Die Verknüpfung zwischen Ereignis und Ereignishandler können Sie auch im Code dynamisch festlegen, z. B. so:


public partial class MainWindow : Window {
  public MainWindow() {
    InitializeComponent();
    button1.Click += new RoutedEventHandler(button1_Click);
  }
  void button1_Click(object sender, RoutedEventArgs e) {
    MessageBox.Show("Im Click-Ereignishandler");
  }
}


Galileo Computing - Zum Seitenanfang

17.7.2 Routed Events topZur vorigen Überschrift

Auch wenn es bis jetzt den Anschein hat, dass die Ereignisse in der WPF keine Besonderheiten bergen, ist dem nicht so. Der Grund ist, dass in einer WPF- Benutzeroberfläche die Elemente ineinander verschachtelt werden können, beispielsweise so:


<Window ...>
  <StackPanel>
    <Button>
      <Canvas>
        <Ellipse></Ellipse>
      </Canvas>
    </Button>
  </StackPanel>
</Window>

Hier enthält der Button ein Canvas-Element, das seinerseits eine Ellipse beschreibt. Klickt der Anwender auf den Button, könnte es sich dabei um das Ellipse-Element handeln, das im Button eingebettet ist. Möchten Sie jedoch sicherstellen, dass beispielsweise das Click-Ereignis der Schaltfläche auch dann ausgelöst wird, wenn der Benutzer die Ellipse trifft, hätten Sie ein kleines Problem.

Jetzt helfen uns die von der WPF eingeführten Routed Events weiter, die wie folgt kategorisiert sind:

  • Direkte Events: die Gruppe der Ereignisse, die nur von dem Element verarbeitet werden, bei dem das Ereignis aufgetreten ist. Diese Ereignisse unterscheiden sich nicht von den sonst im .NET Framework üblichen.
  • Tunneling-Events: Beim Tunneling beginnt die Ereigniskette beim Wurzelelement. In der Regel dürfte es sich dabei um Window handeln. Dieses reicht das Ereignis immer an das nächste untergeordnete Element weiter, das seinerseits wieder das ihm untergeordnete Element informiert. Das geschieht so lange, bis der Auslöser erreicht ist. Die Tunneling-Events sind durch das Präfix Preview gekennzeichnet. Die meisten Routed Events haben ein korrespondierendes Preview-Ereignis.
  • Bubbling-Events: Beim Bubbling von Ereignissen wird der ausgelöste Event an die übergeordnete Komponente in der Hierarchie weitergereicht. Diese kann nun ebenfalls darauf reagieren.

Wird ein Ereignis ausgelöst, das nicht zu den direkten Events gerechnet wird, kommt es zu einer Abfolge von Ereignisauslösungen. Zuerst werden alle Tunneling-Events ausgelöst, wobei das Wurzelelement an der Spitze steht. Anschließend folgt das erste untergeordnete Element. Legen wir das Codefragment von oben zugrunde, würde anschließend das Ereignis im StackPanel ausgelöst, danach im Button, gefolgt vom Canvas und zuletzt im Ellipse-Element – vorausgesetzt, es wurde auf die Ellipse in der Schaltfläche geklickt.

Ist die Kette der Tunneling-Events durchlaufen, geht es mit den Bubbling Events in entgegengesetzter Richtung zurück. Also zuerst mit dem Bubbling-Event in der Ellipse, danach im Canvas-Element, dem Button, dem StackPanel. Den Abschluss bildet das Window.


Hinweis

Um die getunnelten von den gebubbelten Ereignissen unterscheiden zu können, haben alle getunnelten Ereignisse das Präfix Preview.


Abbildung 17.7 verdeutlicht den Zusammenhang. Dabei wurde aber eine etwas einfachere Oberflächenstruktur zugrunde gelegt.

Abbildung 17.7 Abfolge der Routed Events

Routed Events sind eine Spezialform von Ereignissen in der WPF. Es werden dabei alle Handler aufgerufen, die sich bei dem Ereignis registriert haben und zwischen dem Element, bei dem das Ereignis aufgetreten ist, und der Wurzel liegen. Behandelt ein Element das aufgetretene Ereignis nicht, wird die Ereigniskette nicht unterbrochen.


Anmerkung

Im Grunde genommen ist es nicht ganz richtig, bei den direkten Events von Routed Events zu sprechen. Zu den Routed Events gehören eigentlich nur die gebubbelten und getunnelten, also diejenigen, die weitergeleitet werden. Da aber auch die Dokumentation die direkten Events der Gruppe der Routed Events zuordnet, halte ich mich an diese Vorgabe.


Beispielprogramm

Wir sollten uns nun den Ablauf der Routed Events an einem konkreten Beispiel ansehen. Das folgende Beispielprogramm definiert dazu im Window ein Grid, dem mit einem Button und einer ListBox zwei Elemente zugeordnet sind. Der Button enthält ein untergeordnetes Element vom Typ Label. Die ListBox dient ausschließlich zum Anzeigen der Ereigniskette. Alle Elemente reagieren auf das Auslösen der beiden Ereignisse PreviewMouseLeftButtonDown und MouseLeftButtonDown.


// -----------------------------------------------------
// Beispiel: ...\Kapitel 17\RoutedEvents
// -----------------------------------------------------
<Window ...
        MouseLeftButtonDown="Event_MouseDown" 
        PreviewMouseLeftButtonDown="Event_PreviewMouseDown">
  <Grid MouseLeftButtonDown="Event_MouseDown" 
        PreviewMouseLeftButtonDown="Event_PreviewMouseDown">
    <Grid.RowDefinitions>
      <RowDefinition Height="80"/><RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Name="button1" Margin="20"
            MouseLeftButtonDown="Event_MouseDown" 
            PreviewMouseLeftButtonDown="Event_PreviewMouseDown">
      <Label Name="label1" MouseLeftButtonDown="Event_MouseDown" 
             PreviewMouseLeftButtonDown="Event_PreviewMouseDown">
        Klick mich ...
      </Label>
    </Button>
  <ListBox Grid.Row="1" Name="listBox1"></ListBox>
</Grid>
</Window>

In der Code-Behind-Datei sind die beiden Ereignishandler definiert, die auf die Ereignisse reagieren. Je nachdem, welches Element das Ereignis ausgelöst hat, wird in die ListBox eine entsprechende Mitteilung geschrieben.


private void Event_MouseDown(object sender, MouseButtonEventArgs e) {
  if (sender is Button)
    listBox1.Items.Add("BUTTON");
  if (sender is Label)
    listBox1.Items.Add("LABEL");
  else if (sender is Grid)
    listBox1.Items.Add("GRID");
  else if (sender is MainWindow)
    listBox1.Items.Add("WINDOW");
}
 
private void Event_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
  if (sender is Button)
    listBox1.Items.Add("BUTTON-Preview");
  else if (sender is Label)
    listBox1.Items.Add("LABEL-Preview");
  else if (sender is Grid)
    listBox1.Items.Add("GRID-Preview");
  else if (sender is MainWindow)
    listBox1.Items.Add("WINDOW-Preview");
}

Wenn Sie die Anwendung starten und auf die Beschriftung klicken, werden Sie die Ausführungen zu den Routed Events nicht 100%ig bestätigt sehen, denn der Button meldet sich nicht und auch alle nachfolgenden gebubbelten Ereignisse werden nicht mehr ausgelöst (siehe Abbildung 17.8).

Abbildung 17.8 Das Beispielprogramm »RoutedEvents« zur Laufzeit

Der Button ist ein Steuerelement, das wegen des Click-Ereignisses eine Ausnahme darstellt. Das Click-Ereignis schluckt regelrecht alle anderen Ereignisse und bricht die Kette der getunnelten Ereignisse ab.

Gelöst wird dieses Problem durch die Registrierung des allgemeinen MouseDownEvents bei dem entsprechenden Ereignishandler mit der Konstruktormethode AddHandler. Die Registrierung erfolgt im Konstruktor des Window.


button1.AddHandler(MouseDownEvent, 
        new MouseButtonEventHandler(Event_MouseDown), true);

Dieser Methode übergeben Sie zuerst den Ereignistyp und danach ein Delegate auf den Ereignishandler. Der boolesche Parameter gibt an, ob bereits behandelte Ereignisse weiterverarbeitet werden sollen. Tragen Sie hier false ein, wird – falls auf das Label geklickt wird – nur das Ereignis für das Label behandelt. Alle anderen Ereignisse werden nicht mehr registriert.

Trotzdem wird die Anzeige in der ListBox immer noch nicht wie gewünscht sein. Sie müssen außerdem die Eigenschaft Cancel des MouseButtonEventArgs-Parameters auf false setzen, damit die Ereigniskette dort endet, wo sie begonnen hat:


private void Event_MouseDown(object sender, MouseButtonEventArgs e) {
  if (sender is Button) {
    listBox1.Items.Add("BUTTON");
    e.Handled = false;
  }
  ...
}

Ereignisweiterreichung abbrechen

Bei einem Ereignis kann die Ereigniskette jederzeit abgebrochen werden. Dazu dient die Eigenschaft Handled des EventArgs-Parameters, der auf true gesetzt wird. Um bei der Auslösung des Preview-Ereignisses des Grids die Ereigniskette zu beenden, müsste der Code im Ereignishandler wie folgt ergänzt werden:


private void Event_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
  if (sender is Button)
    listBox1.Items.Add("BUTTON-Preview");
  else if (sender is Label)
    listBox1.Items.Add("LABEL-Preview");
  else if (sender is Grid) {
    e.Handled = true;
    listBox1.Items.Add("GRID-Preview");
  }
  else if (sender is Window1)
    listBox1.Items.Add("WINDOW-Preview");
}



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# 2010

Visual C# 2010
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 2010
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.


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern