Erstellen von Formaten und Vorlagen
Formate und Vorlagen von Windows Presentation Foundation (WPF) beziehen sich auf eine Suite von Features (Formate, Vorlagen, Trigger und Storyboards), mit denen Entwickler und Designer visuell überzeugende Effekte erzeugen und die Standardisierung auf ein einheitliches Erscheinungsbild ihres Produkts erreichen. Entwickler und Designer haben zahlreiche Möglichkeiten, die Darstellung von Anwendungen individuell zu gestalten. Allerdings ist ein striktes Modell für Formate und Vorlagen notwendig, um das Erscheinungsbild innerhalb einer Anwendung oder zwischen Anwendungen verwalten und gemeinsam nutzen zu können. Windows Presentation Foundation (WPF) stellt dieses Modell bereit.
Ein anderes Feature des Formatierungsmodells von WPF ist die Trennung von Darstellung und Logik. Dies bedeutet, dass Designer das Erscheinungsbild einer Anwendung nur mit XAML ändern können, während gleichzeitig Entwickler die Programmierlogik mit C# oder Visual Basic bearbeiten.
Es werden keine Datenbindungskonzepte erläutert, sondern es geht vornehmlich um Formate und Vorlagen in Anwendungen. Informationen zur Datenbindung finden Sie unter Übersicht über Datenbindung.
Darüber hinaus sollten Sie mit Ressourcen vertraut sein, da diese eine Wiederverwendung von Formaten und Vorlagen ermöglichen. Weitere Informationen zu Ressourcen finden Sie unter Übersicht über Ressourcen.
Dieses Thema enthält folgende Abschnitte.
- Beispiel für Formate und Vorlagen
- Grundlagen zu Formaten
- Datenvorlagen
- Steuerelementvorlagen
- Trigger
- Freigegebene Ressourcen und Designs
- Verwandte Abschnitte
Beispiel für Formate und Vorlagen
Die in dieser Übersicht verwendeten Codebeispiele basieren auf einem einfachen, in der folgenden Abbildung dargestellten Fotobeispiel:
Diese einfachen Fotobeispiel verwendet Formate und Vorlagen, um eine visuell ansprechende Benutzererfahrung zu erstellen. Das Beispiel verfügt über zwei TextBlock-Elemente und ein ListBox-Steuerelement, das an eine Liste von Bildern gebunden ist. Das vollständige Beispiel finden Sie unter Einführung zum Beispiel zu Stilen und Vorlagen.
Grundlagen zu Formaten
Stellen Sie sich Style als bequeme Möglichkeit vor, um eine Reihe von Eigenschaftswerten auf mehrere Elemente anzuwenden. Betrachten Sie beispielsweise die folgenden TextBlock-Elemente und ihre Standarddarstellung:
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
Sie können die Standarddarstellung ändern, indem Sie Eigenschaften wie FontSize und FontFamily für jedes TextBlock-Element direkt festlegen. Wenn die TextBlock-Elemente einige Eigenschaften gemeinsam nutzen sollen, können Sie im Resources-Abschnitt der XAML-Datei ein Style erstellen, wie im Folgenden gezeigt:
<Window.Resources>
...
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
...
</Window.Resources>
Wenn Sie TargetType des Formats auf den TextBlock-Typ festlegen, wird das Format auf alle TextBlock-Elemente im Fenster angewendet.
Die TextBlock-Elemente werden nun folgendermaßen angezeigt:
Erweitern von Formaten
Sie könnten beispielsweise vorsehen, dass die beiden TextBlock-Elemente dieselben Eigenschaftswerte verwenden sollen, wie FontFamily und die zentrierte HorizontalAlignment, und dass gleichzeitig der Text "My Pictures" zusätzliche Eigenschaften haben soll. Dazu können Sie ein neues Format erstellen, das auf dem ersten Format basiert, wie nachfolgend gezeigt:
<Window.Resources>
...
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
...
</Window.Resources>
Beachten Sie, dass das vorherige Format x:Key erhält. Zum Anwenden des Formats legen Sie die Style-Eigenschaft von TextBlock auf den x:Key-Wert fest, wie nachfolgend gezeigt:
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
Dieses TextBlock-Format hat nun einen HorizontalAlignment-Wert von Center, einen FontFamily-Wert von Comic Sans MS, einen FontSize-Wert von 26 und einen Foreground-Wert, der auf LinearGradientBrush festgelegt ist, wie im Beispiel veranschaulicht. Beachten Sie, dass der FontSize-Wert des Basisformats überschrieben wurde. Wenn mehrere Setter dieselbe Eigenschaft in Style festlegen, hat der zuletzt deklarierte Setter Vorrang.
Im folgenden Beispiel wird gezeigt, wie die TextBlock-Elemente nun dargestellt werden:
Durch dieses TitleText-Format wird das für den TextBlock-Typ erstellte Format erweitert. Sie können auch ein Format erweitern, das über einen x:Key verfügt, indem Sie den x:Key-Wert verwenden. Ein entsprechendes Beispiel ist das für die BasedOn-Eigenschaft zur Verfügung gestellte Beispiel.
Beziehung zwischen der TargetType-Eigenschaft und dem x:Key-Attribut
Wenn Sie die TargetType-Eigenschaft auf TextBlock festlegen, ohne das Format x:Key zuzuweisen, wird es auf alle TextBlock-Elemente angewendet, wie im ersten Beispiel gezeigt. In diesem Fall wird x:Key implizit auf {x:Type TextBlock} festgelegt. Dies bedeutet, dass Style nicht automatisch auf alle TextBlock-Elemente angewendet wird, wenn Sie den x:Key-Wert explizit nicht auf {x:Type TextBlock} festlegen. Stattdessen müssen Sie das Format explizit auf die TextBlock-Elemente anwenden (indem Sie den x:Key-Wert verwenden). Wenn sich das Format im Ressourcenabschnitt befindet und Sie die TargetType-Eigenschaft nicht für das Format festlegen, müssen Sie x:Key angeben.
Die TargetType-Eigenschaft gibt nicht nur einen Standardwert für x:Key an, sondern legt auch fest, auf welchen Typ die Settereigenschaften angewendet werden. Wenn Sie TargetType nicht angeben, müssen Sie die Eigenschaften in den Setter-Objekten mit einem Klassennamen qualifizieren. Dazu verwenden Sie die Syntax Property="ClassName.Property". Statt Property="FontSize" festzulegen, müssen Sie beispielsweise Property auf "TextBlock.FontSize" oder "Control.FontSize" festlegen.
Beachten Sie außerdem, dass viele WPF-Steuerelemente aus einer Kombination von anderen WPF-Steuerelementen bestehen. Das Erstellen eines Formats, das auf alle Steuerelemente eines Typs angewendet wird, kann zu unerwarteten Ergebnissen führen. Wenn Sie z. B. ein Format erstellen, das sich auf den TextBlock-Typ in Window bezieht, wird das Format auf alle TextBlock-Steuerelemente im Fenster angewendet, auch wenn TextBlock Teil eines anderen Steuerelements ist, z. B. von ListBox.
Formate und Ressourcen
Sie können ein Format für jedes Element verwenden, das von FrameworkElement oder FrameworkContentElement abgeleitet ist. Ein Format wird meist als Ressource im Resources-Abschnitt in einer XAML-Datei deklariert, wie in den vorhergehenden Beispielen gezeigt. Da es sich bei Formaten um Ressourcen handelt, unterliegen sie den gleichen Bereichsregeln, die für alle Ressourcen gelten. Wo Sie ein Format deklarieren, hat also Auswirkungen darauf, wo es angewendet werden kann. Wenn Sie das Format z. B. im Stammelement der XAML-Datei der Anwendungsdefinition deklarieren, kann das Format überall in der Anwendung verwendet werden. Wenn Sie eine Navigationsanwendung erstellen und das Format in einer der XAML-Dateien der Anwendung deklarieren, kann das Format nur in dieser XAML-Datei verwendet werden. Weitere Informationen zu Bereichsregeln für Ressourcen finden Sie unter Übersicht über Ressourcen.
Außerdem finden Sie weitere Informationen zu Formaten und Ressourcen unter Gemeinsam genutzte Ressourcen und Designs weiter unten in dieser Übersicht.
Programmgesteuertes Festlegen von Formaten
Wenn Sie einem Element programmgesteuert ein benanntes Format zuweisen möchten, rufen Sie das Format aus der Ressourcenauflistung ab und weisen es der Style-Eigenschaft des Elements zu. Beachten Sie, dass die Elemente in einer Ressourcenauflistung den Typ Object haben. Daher müssen Sie das abgerufene Format vor dem Zuweisen zur Style-Eigenschaft in ein Style umwandeln. Gehen Sie beispielsweise folgendermaßen vor, um das definierte TitleText-Format auf TextBlock mit dem Namen textblock1 festzulegen:
textblock1.Style = CType(Me.Resources("TitleText"), Style)
textblock1.Style = (Style)(this.Resources["TitleText"]);
Sobald ein Format angewendet wurde, ist es versiegelt und kann nicht mehr geändert werden. Wenn Sie ein bereits angewendetes Format dynamisch ändern möchten, müssen Sie ein neues Format erstellen, um das vorhandene zu ersetzen. Weitere Informationen finden Sie in den Ausführungen zur IsSealed-Eigenschaft.
Sie können ein Objekt erstellen, das das anzuwendende Format auf Grundlage benutzerdefinierter Logik auswählt. Ein entsprechendes Beispiel ist das für die StyleSelector-Klasse zur Verfügung gestellte Beispiel.
Bindungen, dynamische Ressourcen und Ereignishandler
Beachten Sie, dass Sie mit der Setter.Value-Eigenschaft eine Bindung als Markuperweiterung oder eine DynamicResource-Markuperweiterung angeben können. Weitere Informationen bieten die Beispiele für die Setter.Value-Eigenschaft.
Bisher wurde in dieser Übersicht nur erläutert, wie Sie mit Settern einen Eigenschaftswert festlegen können. Sie können auch Ereignishandler in einem Format angeben. Weitere Informationen finden Sie unter EventSetter.
Datenvorlagen
In dieser Beispielanwendung ist ein ListBox-Steuerelement an eine Liste von Fotos gebunden:
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
Dieses ListBox sieht zurzeit folgendermaßen aus:
Die meisten Steuerelemente verfügen über Inhalte, die häufig aus den Daten abgerufen werden, an die Sie eine Bindung herstellen. In diesem Beispiel sind die Daten die Liste von Fotos. In WPF definieren Sie die visuelle Darstellung der Daten mithilfe von DataTemplate. Grundsätzlich bestimmen Sie durch die Inhalte von DataTemplate, wie die Daten in der gerenderten Anwendung dargestellt werden.
In der Beispielanwendung hat jedes benutzerdefinierte Photo-Objekt eine Source-Eigenschaft vom Typ string, die den Dateipfad des Bilds angibt. Die Fotoobjekte werden derzeit als Dateipfade angezeigt.
Damit die Fotos als Bilder angezeigt werden, erstellen Sie DataTemplate als Ressource:
<Window.Resources>
...
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
...
</Window.Resources>
Beachten Sie, dass die DataType-Eigenschaft der TargetType-Eigenschaft von Style stark ähnelt. Wenn sich DataTemplate im Ressourcenabschnitt befindet, wenn Sie die DataType-Eigenschaft auf einen Typ festlegen und ihr nicht x:Key zuweisen, wird DataTemplate jedes Mal angewendet, wenn dieser Typ vorkommt. Sie haben immer die Möglichkeit, DataTemplate mit x:Key zuzuweisen und dann als StaticResource für Eigenschaften festzulegen, die DataTemplate-Typen verwenden, z. B. die ItemTemplate-Eigenschaft oder die ContentTemplate-Eigenschaft.
Durch die DataTemplate im oben genannten Beispiel wird im Wesentlichen definiert, dass bei jedem Vorhandensein eines Photo-Objekts dieses als Image innerhalb von Border angezeigt werden soll. Mit dieser DataTemplate sieht die Anwendung jetzt wie folgt aus:
Das Datenvorlagenmodell bietet weitere Features. Wenn Sie beispielsweise Auflistungsdaten anzeigen, die andere Auflistungen enthalten, und dazu einen HeaderedItemsControl-Typ wie Menu oder TreeView verwenden, ist HierarchicalDataTemplate verfügbar. Eine weitere Funktion für Datenvorlagen ist die DataTemplateSelector, mit der Sie eine DataTemplate auswählen können, die auf der Grundlage benutzerdefinierter Logik verwendet werden soll. Weitere Informationen finden Sie unter Übersicht über Datenvorlagen. Dort werden die verschiedenen Features für Datenvorlagen ausführlicher erläutert.
Steuerelementvorlagen
In WPF definiert die ControlTemplate eines Steuerelements dessen Darstellung. Sie können die Struktur und die Darstellung eines Steuerelements ändern, indem Sie eine neue ControlTemplate für das Steuerelement definieren. Meistens reicht die dadurch gewonnene Flexibilität aus, sodass keine eigenen benutzerdefinierten Steuerelemente geschrieben werden müssen. Weitere Informationen finden Sie unter Anpassen der Darstellung eines vorhandenen Steuerelements durch Erstellen einer ControlTemplate.
Trigger
Mit einem Trigger werden Eigenschaften festgelegt oder Aktionen gestartet, z. B. eine Animation beim Ändern eines Eigenschaftswerts oder beim Auslösen eines Ereignisses. Style, ControlTemplate und DataTemplate verfügen über eine Triggers-Eigenschaft, die eine Reihe von Triggern enthalten kann. Es gibt verschiedene Typen von Triggern.
Eigenschaftentrigger
Ein Trigger, der Eigenschaftswerte festlegt oder Aktionen auf der Grundlage des Werts einer Eigenschaft startet, wird als Eigenschaftentrigger bezeichnet.
Um zu veranschaulichen, wie Sie Eigenschaftentrigger verwenden, können Sie die einzelnen ListBoxItem teilweise transparent darstellen, bis sie ausgewählt werden. Mit dem folgenden Format wird der Opacity-Wert von ListBoxItem auf 0.5 festgelegt. Wenn die IsSelected-Eigenschaft true entspricht, wird Opacity jedoch auf 1.0 festgelegt:
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Opacity" Value="1.0" />
</Trigger>
...
</Style.Triggers>
</Style>
In diesem Beispiel wird Trigger zum Festlegen eines Eigenschaftswerts verwendet. Beachten Sie, dass die Trigger-Klasse auch über die EnterActions-Eigenschaft und die ExitActions-Eigenschaft verfügt, die einen Trigger in die Lage versetzen, Aktionen auszuführen.
Beachten Sie, dass der MaxHeight-Wert der ListBoxItem-Eigenschaft 75 lautet. In der folgenden Abbildung ist das dritte Element das ausgewählte Element:
EventTrigger und Storyboards
Ein weiterer Triggertyp ist EventTrigger, der auf Basis des Vorkommens eines Ereignisses eine Reihe von Aktionen startet. Die folgenden EventTrigger-Objekte geben beispielsweise an, dass, wenn der Mauszeiger auf ListBoxItem zeigt, die MaxHeight-Eigenschaft für die Dauer von 0.2 Sekunden eine Animation bis zu dem Wert von 90 ausführt. Wird die Maus von dem Element weg bewegt, kehrt die Eigenschaft für einen Zeitraum von 1 Sekunde zum ursprünglichen Wert zurück. Beachten Sie, dass es nicht erforderlich ist, einen To-Wert für die MouseLeave-Animation anzugeben. Das liegt daran, dass die Animation den ursprünglichen Wert nachverfolgen kann.
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Weitere Informationen finden Sie unter Übersicht über Storyboards.
In der folgenden Abbildung zeigt die Maus auf das dritte Element:
MultiTrigger, DataTrigger und MultiDataTrigger
Neben Trigger und EventTrigger gibt es weitere Typen von Triggern. MultiTrigger ermöglicht das Festlegen von Eigenschaftswerten anhand einer Reihe von Bedingungen. Wenn die Eigenschaft der Bedingung datengebunden ist, verwenden Sie DataTrigger und MultiDataTrigger.
Freigegebene Ressourcen und Designs
Eine typische Windows Presentation Foundation (WPF)-Anwendung kann mehrere Ressourcen für Benutzeroberflächen haben, die in der gesamten Anwendung angewendet werden. Zusammenfassend kann dieser Satz von Ressourcen als das Design für die Anwendung betrachtet werden. Windows Presentation Foundation (WPF) bietet Unterstützung zum Verpacken von Benutzeroberflächenressourcen als Design mit einem Ressourcenwörterbuch, das als ResourceDictionary-Klasse gekapselt wird.
Windows Presentation Foundation (WPF)-Designs werden mithilfe der Mechanismen für Formate und Vorlagen definiert, die von Windows Presentation Foundation (WPF) zum Anpassen der grafischen Darstellung eines Elements verfügbar gemacht werden.
Windows Presentation Foundation (WPF)-Designressourcen werden in eingebetteten Ressourcenwörterbüchern gespeichert. Diese Ressourcenwörterbücher müssen in einer signierten Assembly eingebettet sein. Sie können entweder in derselben Assembly wie der Code oder in einer parallelen Assembly eingebettet werden. Im Fall von PresentationFramework.dll, der Assembly mit Windows Presentation Foundation (WPF)-Steuerelementen, befinden sich die Designressourcen in einer Reihe paralleler Assemblys.
Das Design ist der letzte Ort, an dem nach dem Format eines Elements gesucht wird. Normalerweise beginnt die Suche, indem die Elementstruktur nach einer geeigneten Ressource durchlaufen wird. Danach wird in der Ressourcenauflistung der Anwendung gesucht und zum Schluss das System abgefragt. Auf diese Weise können Anwendungsentwickler das Format für alle Objekte auf Struktur- oder Anwendungsebene neu definieren, bevor das Design erreicht wird.
Sie können Ressourcenwörterbücher als einzelne Dateien definieren, die Ihnen die Wiederverwendung eines Designs über mehrere Anwendungen hinweg ermöglichen. Darüber hinaus können Sie austauschbare Designs erstellen, indem Sie mehrere Ressourcenwörterbücher definieren, die zwar dieselben Ressourcentypen bereitstellen, aber mit anderen Werten. Wenn Sie Skins für eine Anwendung erstellen, empfiehlt es sich, die Formate oder andere Ressourcen auf Anwendungsebene neu zu definieren.
Wenn Sie eine Reihe von Ressourcen, wie Formate und Vorlagen, anwendungsübergreifend gemeinsam nutzen möchten, können Sie eine XAML-Datei erstellen und ResourceDictionary definieren. Werfen Sie z. B. einen Blick auf die folgende Abbildung, die einen Teil des Beispiels zum Formatieren mit ControlTemplates zeigt:
Bei den XAML-Dateien im Beispiel wird Ihnen auffallen, dass alle Dateien über das folgende Element verfügen:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
Die Steuerelemente im Beispiel werden im gleichen Format angezeigt, weil die Datei shared.xaml freigegeben ist. Mit dieser Datei wird ein ResourceDictionary definiert, das eine Reihe von Format- und Pinselressourcen enthält.
Weitere Informationen finden Sie unter Zusammengeführte Ressourcenwörterbücher.
Wenn Sie ein Design für ein benutzerdefiniertes Steuerelement erstellen, sehen Sie sich den Abschnitt zur externen Steuerelementbibliothek unter Übersicht über das Erstellen von Steuerelementen an.
Siehe auch
Aufgaben
Gewusst wie: Suchen von Elementen, die mit einer ControlTemplate generiert wurden
Gewusst wie: Suchen von Elementen, die mit einer DataTemplate generiert wurden