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 26 Dependency Properties
Pfeil 26.1 Die Charakteristik von Abhängigkeitseigenschaften
Pfeil 26.2 Den Wert einer Abhängigkeitseigenschaft bilden
Pfeil 26.3 Definition einer Dependency Property
Pfeil 26.3.1 Registrieren einer Abhängigkeitseigenschaft
Pfeil 26.3.2 Der Eigenschaftswrapper
Pfeil 26.3.3 Die Eigenschaftsmetadaten
Pfeil 26.3.4 Freigabe des spezifischen Eigenschaftswertes
Pfeil 26.3.5 Vererbung von Abhängigkeitseigenschaften
Pfeil 26.4 Validieren einer Abhängigkeitseigenschaft
Pfeil 26.4.1 Validieren mit »ValidateValueCallback«
Pfeil 26.4.2 Validieren mit »CoerceValueCallback«
Pfeil 26.5 Angehängte Eigenschaften (Attached Property)
Pfeil 26.5.1 Angehängte Eigenschaften zur Laufzeit ändern

Galileo Computing - Zum Seitenanfang

26.3 Definition einer Dependency PropertyZur nächsten Überschrift

Dependency Properties können nur in Klassen definiert werden, die von der Klasse DependencyObject abgeleitet sind. Diese Bedingung wird von allen wesentlichen Klassen der WPF erfüllt.

Sehen wir uns jetzt exemplarisch an, wie eine Abhängigkeitseigenschaft mit dem Namen Radius in der Klasse Circle bereitgestellt wird. Grundsätzlich werden alle Abhängigkeitseigenschaften durch ein Objekt vom Typ DependencyProperty beschrieben. In unserem Beispiel lautet die Definition folgendermaßen:

public class Circle : DependencyObject
{
public static readonly DependencyProperty RadiusProperty;
}

Listing 26.1 Grundgerüst einer Abhängigkeitseigenschaft

Wichtig ist, die abhängige Eigenschaft static readonly zu kennzeichnen. Damit werden zwei Verhaltensmerkmale erzwungen:

  • Da eine Abhängigkeitseigenschaft static definiert ist, wird sie nur einmal bereitgestellt – nicht nur für alle Circle-Objekte, sondern auch für alle Objekte, die auf Klassen basieren, die von Circle abgeleitet sind. Alle auf Circle zurückzuführenden Objekte nutzen die Dependency Property gemeinsam.
  • Durch den Modifikator readonly im Zusammenhang mit static wird eine Konstante definiert, deren Wert spätestens im statischen Konstruktor festgeschrieben werden muss. Wie Sie in diesem Kapitel noch lernen werden, zeichnen sich Abhängigkeitseigenschaften durch spezifische, unveränderliche Merkmale aus, so dass die Vorstellung von einer Konstanten auch im Zusammenhang mit den Eigenschaften durchaus gerechtfertigt ist.

Per Konvention muss dem beabsichtigten Eigenschaftsbezeichner (in unserem Beispiel Radius) das Suffix Property angehängt werden. In unserem Beispiel heißt deshalb das Feld der Abhängigkeitseigenschaft RadiusProperty.


Galileo Computing - Zum Seitenanfang

26.3.1 Registrieren einer AbhängigkeitseigenschaftZur nächsten ÜberschriftZur vorigen Überschrift

Mit der Felddefinition alleine ist eine abhängige Eigenschaft natürlich noch nicht vollständig beschrieben. Es fehlen zu diesem Zeitpunkt noch viele Detailinformationen, beispielsweise der von der Eigenschaft beschriebene Datentyp, gegebenenfalls der Standardwert sowie viele andere Merkmale im Umfeld des Einsatzes innerhalb der WPF. Zudem muss eine Abhängigkeitseigenschaft dem WPF-Subsystem bekannt gegeben werden.

Um alle Bedingungen zu erfüllen, muss eine Abhängigkeitseigenschaft mit der statischen Methode Register der Klasse DependencyProperty registriert werden. Die Methode ist vielfach überladen. Sehen wir uns zuerst die einfachste Definition an:

public static DependencyProperty Register(String, Type, Type)

Die drei Parameter lassen sich wie folgt beschreiben:

  • Aus dem ersten Parameter geht der Bezeichner der Eigenschaft hervor. Dieser muss für den an den dritten Parameter übergebenen Besitzertyp eindeutig sein.
  • Der zweite Parameter erwartet die Angabe des Datentyps, den die Eigenschaft beschreibt.
  • Dem dritten Parameter wird mitgeteilt, für welchen Typ die abhängige Eigenschaft registriert werden soll.

Für das Beispiel unserer Abhängigkeitseigenschaft Radius könnte das wie folgt aussehen:

static Circle() {
RadiusProperty = DependencyProperty.Register("Radius", typeof(int),
typeof(Circle));
}

Listing 26.2 Registrierung der Eigenschaft »Radius« als Abhängigkeitseigenschaft


Galileo Computing - Zum Seitenanfang

26.3.2 Der EigenschaftswrapperZur nächsten ÜberschriftZur vorigen Überschrift

Damit würde unsere Abhängigkeitseigenschaft bereits beim WPF-Subsystem registriert und wäre prinzipiell bereits fertig. Mit den folgenden Anweisungen kann bereits zu diesem Zeitpunkt der Radius eines Circle-Objekts wie nachfolgend gezeigt festgelegt werden:

Circle kreis = new Circle();
kreis.SetValue(Circle.RadiusProperty, 118);

Listing 26.3 Festlegen eines Wertes einer Abhängigkeitseigenschaft

Bei SetValue handelt es sich um eine Methode, die von der Basisklasse DependencyObject geerbt wird. Zwei Argumente werden von der Methode erwartet: Im ersten Argument wird die Abhängigkeitseigenschaft angeführt, deren Wert lokal gesetzt werden soll, das zweite Argument beschreibt den Wert selbst.

Sehr ähnlich erfolgt auch die Auswertung. Hierzu dient die Methode GetValue, der die auszuwertende Abhängigkeitseigenschaft als Argument übergeben wird:

kreis.GetValue(Circle.RadiusProperty);

Listing 26.4 Auswerten einer Abhängigkeitseigenschaft

Es fällt in den beiden Codefragmenten auf, dass die traditionelle Zuweisung mit dem Zuweisungsoperator nicht möglich ist und sogar zu einem Fehler führt:

kreis.Radius = 118;

Selbstverständlich möchte man auf die von den CLR-Eigenschaften her gewohnte Variante der Eigenschaftswertfestlegung nicht verzichten. Zudem wäre es nach dem momentanen Stand auch nicht möglich, die Eigenschaft Radius im XAML-Code festzulegen, der immer die Existenz eines get- und set-Zweigs voraussetzt. Deshalb gehört zu jeder Registrierung einer Abhängigkeitseigenschaft auch die Bereitstellung eines Eigenschaftswrappers. Am Beispiel der Eigenschaft Radius würde man den Wrapper wie folgt definieren:

public int Radius
{
get { return (int)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}

Listing 26.5 Eigenschaftswrapper der Eigenschaft »Radius«

Dabei kommen erneut die beiden bereits oben erwähnten Methoden SetValue und GetValue ins Spiel. Das Festlegen und die Auswertung eines Radius kann nun in bekannter Weise mit

Circle kreis = new Circle();
kreis.Radius = 120;
int radius = kreis.Radius;

erfolgen.

In einem Eigenschaftswrapper sollten Sie niemals Code schreiben, der zur Validierung dient oder ein Ereignis auslöst. Der Grund dafür ist, dass viele WPF-spezifische Features keine Notiz vom Eigenschaftswrapper nehmen und mit der Eigenschaft nur unter Aufruf von SetValue und GetValue operieren. Code, der im Eigenschaftswrapper steht, würde also niemals ausgeführt. Zur Validierung eines Eigenschaftswertes bzw. zur Auslösung von Ereignissen bei einer Eigenschaftsänderung stellt die WPF alternativ andere Möglichkeiten bereit, die wir in den nächsten Abschnitten noch kennenlernen werden.

Tatsächlich ist es so, dass der Eigenschaftswrapper eine Voraussetzung dafür ist, dass einer Eigenschaft im XAML-Code ein Wert zugewiesen wird, in unserem Fall beispielsweise mit

<Window.Resources>
<local:Circle x:Key="kreis" Radius="120" />
</Window.Resources>

Natürlich muss dabei gewährleistet sein, dass Radius einen Wert beschreibt, der größer oder gleich null ist.

Erfolgt die Validierung innerhalb des set-Zweigs, z. B.

set {
if (value > 0)
SetValue(RadiusProperty, value);
else
throw new Exception();
}

werden Sie feststellen, dass die Ausnahme nicht ausgelöst wird und das Circle-Objekt tatsächlich einen negativen Radius hat. Das lässt sich sehr einfach beweisen, indem man den folgenden XAML-Code benutzt:

<Window xmlns:local="clr-namespace:WpfApplication1" ...>
<Window.Resources>
<local:Circle x:Key="k" Radius="-120" />
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Source={StaticResource k}, Path=Radius}" />
</Grid>
</Window>

Im TextBlock des Fensters wird der negative Wert angezeigt.


Galileo Computing - Zum Seitenanfang

26.3.3 Die EigenschaftsmetadatenZur nächsten ÜberschriftZur vorigen Überschrift

CLR-Eigenschaften sind recht einfach gestrickt. Sie repräsentieren einen gültigen Wert des Objekts, der über einen set-Zweig gesetzt und über einen get-Zweig ausgewertet wird. Ganz anders sind die an eine Abhängigkeitseigenschaft gestellten Anforderungen. Einige Abhängigkeitseigenschaften üben bei ihrer Änderung einen Einfluss auf die im Elementbaum über- oder untergeordnete Komponente aus, andere verändern das Layout oder werden ihrerseits selbst durch Animationen, Styles oder Templates beeinflusst. WPF-Datenbindungen wären ohne Abhängigkeitseigenschaften in ihren Fähigkeiten nicht denkbar.

Die oben vorgestellte einfache Registrierung einer Dependency Property birgt in sich noch nicht die Möglichkeiten, die aufgezählten Merkmale umzusetzen. Zudem kann mit diesem Ansatz keine Datenvalidierung umgesetzt werden. Um alle Features auszuschöpfen, bietet sich die folgende Überladung der Register-Methode an:

public static DependencyProperty Register(String, 
Type,
Type,
PropertyMetadata,
ValidateValueCallback)

Listing 26.6 Überladung der »Register«-Methode

Die drei ersten Parameter entsprechen exakt denen, die bereits beschrieben worden sind. Der vierte Parameter vom Typ PropertyMetadata legt die WPF-spezifischen Merkmale der Abhängigkeitseigenschaft fest, die sogenannten Eigenschaftsmetadaten. Der fünfte und letzte Parameter beschreibt schließlich einen Delegaten, der für die Validierung des Eigenschaftswertes sorgt.

Sehen wir uns zuerst den vierten Parameter etwas genauer an. Per Definition handelt es sich dabei um ein Objekt vom Typ PropertyMetadata. Im Wesentlichen benutzt man exakt diesen Metadatentyp, wenn einer Abhängigkeitseigenschaft nur ein Standardwert mit auf den Lebensweg gegeben werden soll. Meistens wird das aber nicht ausreichend sein, so dass entweder die von PropertyMetadata abgeleiteten Typen UIPropertyMetadata oder FrameworkPropertyMetadata eingesetzt werden. Dabei erweitert UIPropertyMetadata die Klasse PropertyMetadata nur um Merkmale im Zusammenspiel mit Animationen. In der Regel wird man deshalb auf ein Objekt vom Typ der Ableitung FrameworkPropertyMetadata zurückgreifen.

Die meisten Eigenschaften der Klasse FrameworkPropertyMetadata beschreiben boolesche Werte, die zunächst auf false eingestellt sind. Eine Eigenschaft des Typs ermöglicht zudem die Angabe einer Rückrufmethode (Callback), in der Aufgaben im Zusammenhang mit der Festlegung des Eigenschaftswertes ausgeführt werden können (PropertyChangedCallback). Einer weiteren Eigenschaft kann über einen Delegaten eine Methode zur internen Validierung (CoerceValueCallback) mitgeteilt werden.

Um Ihnen einen Überblick zu verschaffen, sind in Tabelle 26.1 einige Eigenschaften der Klasse FrameworkPropertyMetadata aufgeführt.

Tabelle 26.1 Eigenschaften der Klasse »FrameworkPropertyMetadata« (Auszug)

Eigenschaft Beschreibung

AffectsMeasure

Gibt an, dass nach einer Änderung der Abhängigkeitseigenschaft die Abmessungen neu ermittelt werden.

AffectsArrange

Gibt an, dass nach einer Änderung der Abhängigkeitseigenschaft die Anordnung der enthaltenen Steuerelemente neu ermittelt wird.

AffectsParentMeasure

Gibt an, dass nach einer Änderung der Abhängigkeitseigenschaft die Abmessungen des übergeordneten Steuerelements neu ermittelt werden.

AffectsParentArrange

Gibt an, dass nach einer Änderung der Abhängigkeitseigenschaft die Anordnung der Steuerelemente in der übergeordneten Komponente neu ermittelt wird.

AffectsRender

Gibt an, ob eine Abhängigkeitseigenschaft Einfluss auf das allgemeine Layout hat und möglicherweise das Element zwingt, sich neu zu zeichnen.

BindsTwoWayByDefault

Legt fest, ob die Abhängigkeitseigenschaft das »Two-Way-Binding« unterstützt. Der Standard ist »One-Way-Binding«.

CoerceValueCallback

Beschreibt einen Delegaten auf eine Methode, die den Wert der abhängigen Eigenschaft »korrigiert«.

DefaultValue

Ruft den Standardwert der Eigenschaft ab oder legt ihn fest.

Inherits

Gibt an, ob der Wert der Abhängigkeitseigenschaft vererbbar ist, oder legt den Wert fest.

IsAnimationProhibited

Ist diese Eigenschaft true, kann die Abhängigkeitseigenschaft nicht in einer Animation verwendet werden.

IsNotDataBindable

Diese Eigenschaft wird auf true gesetzt, wenn sie nicht als Ziel einer Datenbindung verwendet werden darf.

Journal

In einer navigierbaren Anwendung soll der Wert der Abhängigkeitseigenschaft im Journal gespeichert werden. Damit bleibt dieser erhalten, wenn zurücknavigiert wird.

PropertyChangedCallback

Eignet sich zum Beispiel auch dazu, hier ein Ereignis auszulösen, das auf Clientseite behandelt werden kann.

Mit diesen Charakteristiken könnte man sich zum Beispiel vorstellen, die Eigenschaft RadiusProperty wie folgt zu initialisieren:

static Circle() {
FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata();
meta.DefaultValue = 0;
meta.AffectsRender = true;
meta.BindsTwoWayByDefault = true;
meta.PropertyChangedCallback = new PropertyChangedCallback(OnRadiusChanged);
RadiusProperty = DependencyProperty.Register("Radius",
typeof(int),
typeof(Circle),
meta);
}

Listing 26.7 Initialisieren und Registrieren von »Radius«

Die Abhängigkeitseigenschaft hat den Standardwert 0. Ferner wird im Bedarfsfall ein Neuzeichnen erzwungen und die Unterstützung des Two-Way-Bindings festgeschrieben. Ändert sich der Wert des Radius, wird die Methode OnRadiusChanged ausgeführt.

Um zumindest einen funktionsfähigen Code zu haben, sollten wir auch die Rückrufmethode OnRadiusChanged bereitstellen. Der Delegate PropertyChangedCallback schreibt vor, dass die Methode zwei Parameter haben muss: Der erste ist vom Typ DependencyObject und liefert die Referenz auf das auslösende Objekt. Der zweite Parameter ist vom Typ DependencyPropertyChangedEventArgs. Die Eigenschaften des EventArgs-Objekts liefern neben dem Bezeichner der auslösenden Eigenschaft auch deren alten und neuen Wert ab. Im nachfolgenden Code benutzen wir die Callback-Methode dazu, ein Ereignis auszulösen.

public class Circle : DependencyObject {
public event EventHandler RadiusChanged;
public static readonly DependencyProperty RadiusProperty;

static Circle() {
[...]
}

public static void OnRadiusChanged(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Circle kreis = (Circle)sender;
if( kreis.RadiusChanged != null)
kreis.RadiusChanged(kreis, null);
}

public int Radius {
get { return (int)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}

}

Listing 26.8 Klasse »Circle« mit Callback-Methode

Die Enumeration »FrameworkMetadataOptions«

Der Konstruktor der Klasse FrameworkPropertyMetadata ist überladen. Darunter sind auch mehrere Konstruktoren zu finden, die einen Parameter vom Typ FrameworkPropertyMetadataOptions beschreiben. Bei diesem Typ handelt es sich um eine Enumeration, deren Member sich bitweise verknüpfen lassen. Die einzelnen Mitglieder beschreiben die Eigenschaften der Klasse FrameworkPropertyMetadata, die vom Typ Boolean sind. Wird ein Member dieser Enumeration angegeben, wird das vom Compiler entsprechend als true bewertet.

Somit ließe sich die Initialisierung des Objekts RadiusProperty alternativ auch folgendermaßen umsetzen:

static Circle() {
FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);
meta.PropertyChangedCallback = new PropertyChangedCallback(OnRadiusChanged);
RadiusProperty = DependencyProperty.Register("Radius", typeof(int),
typeof(Circle), meta);
}

Listing 26.9 Alternative Angabe der Metadaten einer Dependency Property

Visual Studio 2012 bietet ein Code-Snippet an, mit dem man sehr einfach das Grundgerüst einer Dependency Property erstellen kann. Geben Sie dazu einfach in der Klasse propdp ein, und drücken Sie anschließend die Tabulator-Taste.


Galileo Computing - Zum Seitenanfang

26.3.4 Freigabe des spezifischen EigenschaftswertesZur nächsten ÜberschriftZur vorigen Überschrift

In manchen Situationen kann es sinnvoll sein, den individuellen lokalen Eigenschaftswert einer Komponente zu löschen, um wieder auf den Standardwert zurückzugreifen. Die einfache Übergabe des Standardwertes an die Eigenschaft reicht dazu nicht aus. Stattdessen ruft man die Methode ClearValue auf und übergibt ihr als Argument die Abhängigkeitseigenschaft, z. B.:

kreis.ClearValue(Circle.RadiusProperty);

Listing 26.10 Zurücksetzen der Eigenschaft auf die Standardeinstellung


Galileo Computing - Zum Seitenanfang

26.3.5 Vererbung von AbhängigkeitseigenschaftenZur vorigen Überschrift

Auf alle Eigenschaften der Klasse FrameworkPropertyMetadata (siehe Tabelle 26.1) einzugehen, würde in diesem Buch zu weit führen. Aber lassen Sie uns einen Blick auf eine besondere Eigenschaft werfen. Eine Option ist die Einstellung Inherits. Auch wenn der Bezeichner im ersten Moment etwas anderes suggeriert, mit der aus der OOP bekannten Vererbung hat diese Einstellung nichts zu tun. Stattdessen gibt die Option Inherits an, ob der Wert der Abhängigkeitseigenschaft an die im Elementbaum untergeordneten Elemente weitergereicht wird. Ein einfaches Beispiel soll das Verhalten verdeutlichen:

<Window ...
Title="MainWindow" Height="350" Width="525" FontSize="26">
<StackPanel>
<Button>
<Label>Hallo</Label>
</Button>
</StackPanel>
</Window>

Listing 26.11 Weitervererbte Eigenschaft »FontSize«

Die Eigenschaft FontSize wird für das Window-Element festgelegt. FontSize ist eine Eigenschaft, die »weitervererbt« wird. Das hat zur Konsequenz, dass das weiter unten im Elementbaum positionierte Label den Text Hallo in der Schriftgröße 26 anzeigt.

Einige Controls werden ein davon abweichendes Verhalten zeigen. Dazu gehören unter anderem Menu, ToolTip und auch StatusBar. Der Grund ist, dass diese Komponenten die Schriftgröße intern selbst festlegen. Genau genommen beziehen diese Steuerelemente ihre Informationen aus den aktuellen Systemeinstellungen.



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