Rheinwerk Computing < openbook > Rheinwerk 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

Jetzt 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 23 Konzepte von WPF
Pfeil 23.1 Anwendungsspezifische Ressourcen
Pfeil 23.2 Anwendungsübergreifende Ressourcen
Pfeil 23.2.1 Mehrere Ressourcenwörterbücher
Pfeil 23.2.2 Die Suche nach einer Ressource
Pfeil 23.3 Logische Ressourcen
Pfeil 23.3.1 Statische Ressourcen
Pfeil 23.3.2 Dynamische Ressourcen
Pfeil 23.3.3 Ressourcen mit C#-Code bearbeiten
Pfeil 23.3.4 Abrufen von Systemressourcen
Pfeil 23.4 Styles
Pfeil 23.4.1 Einfache Styles
Pfeil 23.4.2 Typisierte Styles
Pfeil 23.4.3 Erweitern von Styles
Pfeil 23.4.4 EventSetter
Pfeil 23.5 Trigger
Pfeil 23.5.1 Eigenschaftstrigger
Pfeil 23.5.2 Datentrigger
Pfeil 23.5.3 Ereignistrigger
Pfeil 23.6 Templates
Pfeil 23.6.1 Allgemeines zu »ControlTemplates«
Pfeil 23.6.2 Definition innerhalb eines Styles
Pfeil 23.7 Ermitteln des visuellen Elementbaums
Pfeil 23.7.1 Das Tool »Expression Blend«
Pfeil 23.7.2 Standard-Template mit Code abfragen

Rheinwerk Computing - Zum Seitenanfang

23.6 TemplatesZur nächsten Überschrift

Um mehreren Steuerelementen ein identisches Layout zu verleihen und dabei redundanten Code zu vermeiden, eignen sich Styles ganz hervorragend. Die grundlegende optische Darstellung der Steuerelemente wird dabei aber nicht verändert, ein Button-Steuerelement wird beispielsweise immer als Rechteck dargestellt. Die Möglichkeiten eines Styles sind daher vergleichsweise beschränkt.

Templates gehen in dieser Hinsicht einen Schritt weiter, denn sie gestatten die individuelle Gestaltung des Layouts der Steuerelemente durch eigenen XAML-Code, ohne die elementare Funktionsweise dabei zu beeinflussen. Möglich wird das durch die konsequente Aufteilung von Logik und Darstellung in WPF. Unter Windows Forms waren Logik und Darstellung so miteinander verkoppelt, dass man eigene Steuerelemente entwickeln musste, um eine individuelle Darstellung zu erzielen. Das war mit nicht unerheblichem Programmieraufwand verbunden, weil die Logik in das neue Steuerelement eingepflegt werden musste.

Doch nicht nur das Layout eines Steuerelements kann mit einem Template verändert werden. Auch die Darstellung von einzelnen Daten oder Datengruppen lässt sich mit Templates nach eigenen Vorstellungen anpassen. Deshalb werden in der WPF auch drei Arten von Templates unterschieden:

  • ControlTemplates
  • ItemsPanelTemplates
  • DataTemplates

Mit einem ControlTemplate wird das Layout eines Steuerelements beschrieben, und ein DataTemplate übernimmt die Darstellung der Daten eines bestimmten Typs in einem ContentControl. Mit ItemsPanelTemplate passen wir das Layout eines Steuerelements an, das mehrere Elemente aufnehmen kann. Dabei handelt es sich um die Steuerelemente, die von der Klasse ItemsControl abgeleitet sind (ListBox, ComboBox, Menu usw.).

In diesem Kapitel werden wir uns ausschließlich mit dem ControlTemplate beschäftigen, da DataTemplates und ItemsPanelTemplates meistens im Zusammenhang mit der Darstellung eingesetzt werden. Dieses Thema wird uns aber erst in Kapitel 24 und 25 beschäftigen.


Rheinwerk Computing - Zum Seitenanfang

23.6.1 Allgemeines zu »ControlTemplates«Zur nächsten ÜberschriftZur vorigen Überschrift

ControlTemplates sind für das Layout der Steuerelemente verantwortlich. Es ist nicht sehr schwierig, das Standard-Template eines Steuerelements durch ein eigenes auszutauschen, um einem Steuerelement ein individuelles Layout zu verpassen.

Nicht alle Steuerelemente lassen sich mit Templates umgestalten. Templates sind nur bei Steuerelementen möglich, die von der Klasse Control abgeleitet sind. Bei allen anderen erfolgt die Darstellung auch weiterhin mit Programmcode. Einige Steuerelemente bieten zudem die Möglichkeit, Teilbereiche zu ändern.

Grundlagen der Templates

ControlTemplates werden durch die gleichnamige Klasse beschrieben und können im XAML-Code sehr einfach definiert werden. Die Inhaltseigenschaft VisualTree von ControlTemplate beschreibt den visuellen Elementbaum, der für die Darstellung des Steuerelements verantwortlich ist. Am Beispiel einer Schaltfläche soll das erläutert werden. Dabei werden wir schrittweise die Darstellung eines Button-Objekts ändern, so dass am Ende eine optisch ansprechende, elliptische Schaltfläche das Ergebnis sein wird. Das folgende Listing soll uns als Ausgangspunkt dienen. Hier wird zunächst nur das Layout der neuen Schaltfläche beschrieben.

[...]
<Window.Resources>
<ControlTemplate x:Key="ellipseButton">
<Grid>
<Ellipse Name="ellipse" Width="100" Height="60">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="Wheat" />
<GradientStop Offset="1" Color="DarkGray" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</ControlTemplate>
<Window.Resources>
[...]

Listing 23.28 Das Layout einer benutzerdefinierten Schaltfläche

Innerhalb von ControlTemplate ist ein Grid-Element mit nur einer Zelle definiert. Das ist vorteilhaft, da das Grid die Größe aller enthaltenen Elemente automatisch anpasst. Natürlich ist auch möglich, einen anderen, beliebigen Container zu verwenden.

Innerhalb des Grid wird ein Ellipse-Objekt beschrieben. Dieses soll unseren elliptischen Button darstellen. Die Eigenschaften Height und Width sind derzeit noch statisch definiert. Das hat zur Folge, dass die Ellipse immer gleich groß dargestellt wird, unabhängig davon, welche Abmessungen die Schaltfläche tatsächlich aufweist. Wir werden später noch eine entsprechende Anpassung vornehmen müssen, damit sich die Ellipse den Außenabmessungen der Schaltfläche anpasst. Das Füllmuster der Ellipse weist einen Farbverlauf auf, auf den an dieser Stelle aber nicht weiter eingegangen wird.

Jedes Template muss mit einem eindeutigen Identifier signiert werden, der dem Attribut x:Key bekannt gegeben wird. Im Gegensatz zu einem Style ist dieses Attribut keine Option, sondern Pflicht. Das Template kann zudem von jedem Steuerelementtyp verwendet werden, vorausgesetzt, er ist von Control abgeleitet. Möchten Sie das Template aber auf einen bestimmten Typ beschränken, müssen Sie zusätzlich noch das Attribut TargetType angeben, z. B.:

<ControlTemplate x:Key="ellipseButton" TargetType="Button">
[...]
</ControlTemplate>

Listing 23.29 Struktur des Elements »ControlTemplate«

Templates lassen sich innerhalb eines beliebigen Resources-Abschnitts definieren. Man wird sich aber kaum die Mühe machen, ein Template nur für ein oder mehrere Steuerelemente in einem Fenster zu entwickeln. Vielmehr soll die ganze Anwendung davon profitieren. Deshalb sind Templates meistens global innerhalb der Datei App.xaml oder gar in einem Ressourcenwörterbuch definiert.

Jeder Steuerelementtyp hat sein eigenes, spezifisches Standard-Template, das von der WPF vorgegeben wird. Unser Ziel ist es, dieses durch unser eigenes Template zu ersetzen. Dazu stellen die Steuerelemente, die von Control abgeleitet sind, die Eigenschaft Template bereit. Dieser geben wir mit StaticResource den Verweis auf unser Template bekannt:

<Button Template="{StaticResource ellipseButton}">
Button
</Button>

Listing 23.30 Eine Schaltfläche mit einem »ControlTemplate« verbinden

Abbildung

Abbildung 23.7 Button in elliptischer Darstellung

Verfeinerung des Entwurfs

Obwohl das Ergebnis zum jetzigen Zeitpunkt durchaus schon optisch respektabel ist, müssen wir selbstkritisch noch die folgenden Mängel feststellen:

  • Die Größe der angezeigten Ellipse ist unveränderlich. Auch eine Änderung der Eigenschaften Height und Width beispielsweise im Eigenschaftsfenster der Schaltfläche oder im XAML-Code wird daran nichts ändern, die Ellipse erscheint weiterhin in derselben Größe.
  • Unsere neue Schaltfläche weist keine Beschriftung auf. Hier sind anscheinend noch Stellschrauben zu bedienen, um die Inhaltseigenschaft der zugrunde liegenden Schaltfläche auf unsere eigene Schaltfläche zu übertragen.
  • Unsere Benutzerschaltfläche zeigt keine optischen Änderungen, wenn die Maus darüber gezogen wird oder sie gar angeklickt wird, obwohl sie durchaus auf das Click-Ereignis reagiert.

Diesen drei Punkten wollen wir uns nun der Reihe nach widmen und dabei weiter gehende Erkenntnisse hinsichtlich der Templates sammeln.

Wertübernahme mit »TemplateBinding«

Damit das ControlTemplate auch in verschiedenen Größen dargestellt werden kann, muss es die entsprechenden Daten aus dem übergeordneten Element beziehen. Bei dem übergeordneten Element handelt es sich um dasjenige, dem das ControlTemplate als Vorlage zugewiesen wird. In unserem Beispiel handelt es sich also um einen Button. Die Datenübernahmen geschehen mittels Datenbindung, die mit der Markup Extension TemplateBinding umgesetzt wird. TemplateBinding muss immer dort angegeben werden, wo Werte aus den Eigenschaften benötigt werden.

In unserem Beispiel ist die elliptische Form noch wie folgt definiert:

<Ellipse Name="ellipse" Width="100" Height="60">

Wir ergänzen das Ellipse-Element nun wie folgt und zeichnen auch gleichzeitig einen Rahmen um die äußere Kontur.

<Ellipse Name="ellipse"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Stroke="Black"
StrokeThickness="1">

Listing 23.31 Datenübernahme mit »TemplateBinding«

In ähnlicher Weise widmen wir uns auch noch der Eigenschaft Content des übergeordneten Steuerelements. Denn bisher können wir von einer der herausragenden Eigenschaften der WPF, dem Verschachteln mehrerer Steuerelemente, noch nicht profitieren. Zudem bleibt uns noch immer die Möglichkeit verwehrt, den elliptischen Button zu beschriften. Hier bietet die WPF das Element ContentPresenter an, das speziell für den Entwurf von Templates bereitgestellt wird.

<ControlTemplate x:Key="ellipseButton" TargetType="Button">
<Grid>
<Ellipse ...>
[...]
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" >
</ContentPresenter>
</Grid>
</ControlTemplate>

Listing 23.32 Die »Content«-Eigenschaft übernehmen

Da wir den Inhalt nicht am Bezugspunkt links oben ausgerichtet haben wollen, sondern zentral innerhalb der Ellipse, wird der Inhalt mit HorizontalAlignment und VerticalAlignment mittig dargestellt. Mit der Markup Extension TemplateBinding binden wird die Content-Eigenschaft des ContentPresenter-Elements an die Content-Eigenschaft der übergeordneten Schaltfläche.

Interaktivität mit Trigger

Obwohl unser Template schon recht weit gediehen ist, reagiert es immer noch nicht auf den Anwender. Zieht man zum Beispiel mit der Maus über die Komponente, signalisiert keine farbliche Änderung, dass das Steuerelement nun aktiv ist und angeklickt werden kann.

Zur Lösung dieser Problematik bieten sich wieder Trigger an, ähnlich wie bei den Styles. Trigger werden der Eigenschaft Triggers des ControlTemplate zugewiesen. Das folgende Beispiel beschreibt die Änderung der Darstellung, wenn mit der Maus über die Ellipse, also den Button, gezogen wird. Ist der Wert von IsMouseOver true, wird der Trigger ausgelöst. Mit Hilfe von Setter-Elementen werden dann die Eigenschaften des Steuerelements verändert. Im Code des Beispiels wird nur der Rand der Ellipse in der Farbe Rot angezeigt.

<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="ellipse" Property="StrokeThickness" Value="3" />
<Setter TargetName="ellipse" Property="Stroke" Value="Red" />
</Trigger>
[...]
</ControlTemplate.Triggers>

Listing 23.33 Triggern der Maus

Im Allgemeinen wird diese Verhaltensänderung für sich alleine nicht ausreichen. Klickt der Anwender auf die Schaltfläche, soll vermutlich auch die Füllfarbe die Aktion visualisieren. Hierzu ist ein zweiter Trigger erforderlich, der ausgelöst wird, wenn die Eigenschaft IsPressed den Wert true hat. Der entsprechende XAML-Code wäre dann zum Beispiel wie folgt:

<ControlTemplate x:Key="ellipseButton" TargetType="Button">
<Grid>
[...]
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="ellipse"
Property="StrokeThickness" Value="3" />
<Setter TargetName="ellipse"
Property="Stroke" Value="Red" />
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">
<Setter TargetName="ellipse" Property="StrokeThickness" Value="2" />
<Setter TargetName="ellipse" Property="Stroke" Value="Red" />
<Setter TargetName="ellipse" Property="Fill">
<Setter.Value>
<RadialGradientBrush>
<GradientStop Offset="0" Color="Blue" />
<GradientStop Offset="1" Color="WhiteSmoke" />
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Listing 23.34 Komplette Trigger des Beispiels

In Abbildung 23.8 sehen Sie das Ergebnis der Bemühungen. Links ist die »normale« Darstellung des Buttons zu sehen, rechts ein Button, während auf ihn geklickt wird.

Abbildung

Abbildung 23.8 »EllipseButton«-ControlTemplate

Das komplette Beispiel des ControlTemplates finden Sie auf der Buch-DVD unter
Beispiele\Kapitel 23\ControlTemplateSample
.


Rheinwerk Computing - Zum Seitenanfang

23.6.2 Definition innerhalb eines StylesZur vorigen Überschrift

Häufig wird innerhalb einer Anwendung ein Template definiert, das auf alle Steuerelemente des gleichen Typs angewendet werden soll, so dass das Template anwendungsintern zum Standard-Template der Steuerelemente mutiert. Dafür sind Styles besonders gut geeignet. Damit erübrigt sich ein manuelles Zuweisen des Templates.

Je nachdem, wo das Template definiert ist, wird zwischen einer expliziten und impliziten Definition von ControlTemplates unterschieden. Das folgende Codefragment zeigt ein explizites Template. Hier wird in der Eigenschaft Template des Setter-Elements auf die statische Ressource verwiesen.

<ControlTemplate x:Key="EllipseButton" TargetType="Button">
[...]
</ControlTemplate>
<Style x:Key="MyEllipseButton"
TargetType="{x:Type Button}" >
<Setter Property="Template" Value="{StaticResource EllipseButton}" />
</Style>

Listing 23.35 Explizites ControlTemplate

Im Steuerelement wird anschließend der Style bekannt gegeben.

<Button Style="{StaticResource MyEllipseButton}" ... />

Das ControlTemplate kann auch innerhalb eines Styles definiert werden. Das erleichtert nicht nur die Wartbarkeit, sondern es entfällt beim Steuerelement auch die Angabe der Ressource mit Template oder Style.

<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Listing 23.36 Implizites ControlTemplate



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.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
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.


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