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 29 Benutzerdefinierte Controls
Pfeil 29.1 Erstellen eines benutzerdefinierten Steuerelements
Pfeil 29.2 Der XAML-Code
Pfeil 29.3 Die Programmlogik des Steuerelements
Pfeil 29.3.1 Die Eigenschaften
Pfeil 29.3.2 Ein Ereignis bereitstellen
Pfeil 29.3.3 Das Steuerelement um einen »Command« ergänzen
Pfeil 29.4 Testanwendung

Galileo Computing - Zum Seitenanfang

29.3 Die Programmlogik des SteuerelementsZur nächsten Überschrift


Galileo Computing - Zum Seitenanfang

29.3.1 Die EigenschaftenZur nächsten ÜberschriftZur vorigen Überschrift

Das Steuerelement soll insgesamt vier Eigenschaften veröffentlichen, die als Abhängigkeitseigenschaften implementiert werden sollen. In Kapitel 26 wurde beschrieben, dass dazu static readonly-Eigenschaften bereitgestellt werden müssen, die vom Typ DependencyProperty sind.

Im ersten Schritt wollen wir diese Felder in der Klasse ColorMixer codieren.

// Felder

public static readonly DependencyProperty ColorProperty;
public static readonly DependencyProperty RedProperty;
public static readonly DependencyProperty GreenProperty;
public static readonly DependencyProperty BlueProperty;

Listing 29.3 Die Abhängigkeitseigenschaften

Wir sollten auch sofort für alle vier Eigenschaften einen Wrapper bereitstellen, damit die Eigenschaften nach außen hin wie jede übliche CLR-Property auftreten.

public Color Color {
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }

}

public byte Red {
get { return (byte)GetValue(RedProperty); }
set { SetValue(RedProperty, value); }
}

public byte Green {
get { return (byte)GetValue(GreenProperty); }
set { SetValue(GreenProperty, value); }
}

public byte Blue {
get { return (byte)GetValue(BlueProperty); }
set { SetValue(BlueProperty, value); }
}

Listing 29.4 Die Eigenschaftswrapper der Klasse »ColorMixer«

Initialisiert werden die in Listung 29.3 erstellten Felder im statischen Konstruktor mit der statischen Methode Register der Klasse DependencyProperty. Dabei werden nicht nur die tatsächlich von den Eigenschaften beschriebenen Datentypen festgelegt, sondern auch die spezifischen Charakteristiken der Abhängigkeitseigenschaften. Dazu wird bei der Initialisierung ein Objekt des Typs FrameworkPropertyMetadata übergeben, in dem alle Charakteristiken beschrieben werden.

Einen Umstand können wir bei der Eigenschaftsinitialisierung sofort berücksichtigen. Ändert sich eine der drei Eigenschaften Red, Green oder Blue, ist auch die Eigenschaft Color davon betroffen und muss neu festgelegt werden. Wird andererseits die Eigenschaft Color verändert, hat das Einfluss auf die durch Red, Green und Blue beschriebenen jeweiligen Anteile.

Um die beschriebene Synchronisation der Farben zu gewährleisten, stellen wir Methoden bereit, die an den Delegaten vom Typ PropertyChangedCallback im FrameworkPropertyMetadata-Objekt gebunden werden. Die Methodenbezeichner sollen ColorPropertyChanged und RGBPropertyChanged lauten.

Damit sieht der statische Konstruktor wie folgt aus:

static ColorMixer()
{
ColorProperty = DependencyProperty.Register("Color",
typeof(Color), typeof(ColorMixer),
new FrameworkPropertyMetadata(Colors.Black,
new PropertyChangedCallback(ColorPropertyChanged)));

RedProperty = DependencyProperty.Register("Red",
typeof(byte), typeof(ColorMixer),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(RGBPropertyChanged)));

GreenProperty = DependencyProperty.Register("Green",
typeof(byte), typeof(ColorMixer),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(RGBPropertyChanged)));

BlueProperty = DependencyProperty.Register("Blue",
typeof(byte), typeof(ColorMixer),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(RGBPropertyChanged)));
}

Listing 29.5 Der statische Konstruktor der Klasse »ColorMixer«

Jetzt müssen wir die beiden Methoden ColorPropertyChanged und RGBPropertyChanged implementieren. Widmen wir uns zuerst der Methode RGBPropertyChanged, die immer dann ausgeführt wird, wenn sich eine der Eigenschaften Red, Green oder Blue verändert. Dem EventArgs-Objekt können wir aus dessen Eigenschaft Property die Eigenschaft entnehmen, die verändert worden ist. Das ist wichtig, denn die Gesamteigenschaft Color muss dann in ihrem entsprechenden Farbanteil angepasst werden. Den neuen Wert kann man der NewValue-Eigenschaft des EventArgs-Objekts entnehmen.

private static void RGBPropertyChanged(DependencyObject sender, 
DependencyPropertyChangedEventArgs e)
{
ColorMixer colorPicker = sender as ColorMixer;
Color color = colorPicker.Color;
if (e.Property == RedProperty)
color.R = (byte)e.NewValue;
else if (e.Property == GreenProperty)
color.G = (byte)e.NewValue;
else if (e.Property == BlueProperty)
color.B = (byte)e.NewValue;
colorPicker.Color = color;
}

Listing 29.6 Die Methode »RGBPropertyChanged«

Die vorgesehene Methode ColorPropertyChanged ist sehr ähnlich zu implementieren.

private static void ColorPropertyChanged(DependencyObject sender, 
DependencyPropertyChangedEventArgs e) {
ColorMixer colorPicker = (ColorMixer)sender;
Color newColor = (Color)e.NewValue;
colorPicker.Red = newColor.R;
colorPicker.Green = newColor.G;
colorPicker.Blue = newColor.B;
}

Listing 29.7 Die Methode »ColorPropertyChanged«


Galileo Computing - Zum Seitenanfang

29.3.2 Ein Ereignis bereitstellenZur nächsten ÜberschriftZur vorigen Überschrift

Nun möchten wir sicherlich auch die Möglichkeit eröffnen, dem Anwender durch eine Benachrichtigung mitzuteilen, dass sich der Farbwert des Steuerelements verändert hat. Dazu müssen wir einen Event in der Methode ColorPropertyChanged auslösen. Im Grunde genommen würde es ausreichen, ein herkömmliches Ereignis zu programmieren. Damit würden wir uns aber der Möglichkeit berauben, das Ereignis im Elementbaum nach oben blubbern zu lassen, um den Event an einer im Elementbaum höheren Stelle zu behandeln. Somit bleibt die Idee der Implementierung eines Routed Events, den wir ColorChanged nennen wollen.

Im ersten Schritt legen wir dazu eine statische, schreibgeschützte Variable an, die mit der Methode RegisterRoutedEvent der Klasse EventManager beim System registriert wird. Natürlich dürfen wir nicht vergessen, mit einem standardmäßigen Ereigniswrapper das Ereignis zu veröffentlichen, um das Registrieren und Deregistrieren mehrerer Ereignishandler zu ermöglichen.

public static readonly RoutedEvent ColorChangedEvent = 
EventManager.RegisterRoutedEvent("ColorChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<Color>),
typeof(ColorMixer));

public event RoutedPropertyChangedEventHandler<Color> ColorChanged {
add { AddHandler(ColorChangedEvent, value); }
remove { RemoveHandler(ColorChangedEvent, value); }
}

Listing 29.8 Bereitstellung des Ereignisses »ColorChanged«

Der Typ des EventArgs-Parameters ist RoutePropertyChangedEventArgs<Color>, in dem sowohl der alte als auch der neue Farbwert bereitgestellt werden. Da wir darüber hinaus die Ereignisauslösung in einer separaten Methode kapseln wollen, die wir OnColorChanged nennen, bietet es sich an, den alten und neuen Wert an die kapselnde Methode zu übergeben.

public partial class ColorPicker : UserControl
{
[...]

private static void ColorPropertyChanged( ... )
{
ColorMixer colorPicker = (ColorMixer)sender;
Color newColor = (Color)e.NewValue;
colorPicker.Red = newColor.R;
colorPicker.Green = newColor.G;
colorPicker.Blue = newColor.B;

// zusätzliche Anweisungen

Color oldColor = (Color)e.OldValue;
colorPicker.OnColorChanged(oldColor, newColor);
}

private void OnColorChanged(Color oldValue, Color newValue) {
RoutedPropertyChangedEventArgs<Color> args =
new RoutedPropertyChangedEventArgs<Color>(oldValue, newValue);
args.RoutedEvent = ColorMixer.ColorChangedEvent;
RaiseEvent(args);
}
}

Listing 29.9 Ereignisauslösung in der Klasse »ColorMixer«


Galileo Computing - Zum Seitenanfang

29.3.3 Das Steuerelement um einen »Command« ergänzenZur vorigen Überschrift

Kommen wir nun zum letzten Schritt. Wir wollen das Steuerelement um ein Kommando ergänzen, das es uns ermöglicht, den letzten Farbwechsel wieder rückgängig zu machen. In der Klasse ApplicationCommands finden wir das dazu passend bereitgestellte Kommando Undo.

Ehe wir uns an die Programmierung machen, müssen wir erst sicherstellen, dass der alte Wert auch gespeichert wird. Dazu eignet sich ein Feld in der Klasse. Wir wollen es oldColor nennen. Es ist empfehlenswert, das Feld als Nullable-Typ zu deklarieren, damit beim Start der Anwendung von dem Feld kein Farbwert beschrieben wird.

public partial class ColorPicker : UserControl {
private Color? previousColor;

[...]
}

Listing 29.10 Ergänzung der Klasse »ColorMixer« um das Feld »oldColor«

Für die Bereitstellung des Kommandos eignet sich die Klasse CommandManager mit ihrer statischen Methode RegisterClassCommandBinding. Die Methode wird ebenfalls im statischen Konstruktor aufgerufen:

CommandManager.RegisterClassCommandBinding(typeof(ColorMixer), 
new CommandBinding(ApplicationCommands.Undo,
UndoCommand_Executed,
UndoCommand_CanExecute));

Listing 29.11 Registrieren des »Command«-Objekts beim System

Zur Fertigstellung unseres Controls bleibt noch, die beiden Ereignisse CanExcecute und Execute zu implementieren.

private static void UndoCommand_CanExecute(object sender, 
CanExecuteRoutedEventArgs e){

ColorMixer colorPicker = (ColorMixer)sender;
e.CanExecute = colorPicker.oldColor.HasValue;
}

private static void UndoCommand_Executed(object sender,
ExecutedRoutedEventArgs e)
{
ColorMixer colorPicker = (ColorMixer)sender;
colorPicker.Color = (Color)colorPicker.oldColor;
}

Listing 29.12 Die Ereignisse »Execute« und »CanExecute«



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