Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die Gestaltung und Vorlagen von Windows Presentation Foundation (WPF) beziehen sich auf eine Reihe von Features, mit denen Entwickler und Designer visuell ansprechende Effekte und ein einheitliches Erscheinungsbild für ihr Produkt erstellen können. Beim Anpassen der Darstellung einer App möchten Sie ein starkes Stil- und Vorlagenmodell haben, das die Wartung und das Teilen des Aussehens innerhalb und zwischen Apps ermöglicht. WPF stellt dieses Modell bereit.
Ein weiteres Feature des WPF-Formatmodells ist die Trennung von Präsentation und Logik. Designer können gleichzeitig an der Darstellung einer App arbeiten, indem sie nur XAML verwenden, während Entwickler mit C# oder Visual Basic an der Programmierlogik arbeiten.
Diese Übersicht konzentriert sich auf die Formatierungs- und Vorlagenaspekte der App und behandelt keine Datenbindungskonzepte. Informationen zur Datenbindung finden Sie unter Data Binding Overview.
Es ist wichtig, Ressourcen zu verstehen, mit denen Stile und Vorlagen wiederverwendet werden können. Weitere Informationen zu Ressourcen finden Sie unter Übersicht über XAML-Ressourcen.
Beispiel
Der in dieser Übersicht bereitgestellte Beispielcode basiert auf einer einfachen Fotobrowsenanwendung , die in der folgenden Abbildung gezeigt wird.
In diesem einfachen Fotobeispiel werden Stile und Vorlagen verwendet, um eine visuell ansprechende Benutzererfahrung zu schaffen. Das Beispiel enthält zwei TextBlock Elemente und ein ListBox Steuerelement, das an eine Liste von Bildern gebunden ist.
Das vollständige Beispiel finden Sie unter "Einführung in Styling und Templating: Beispiel".
Stile
Sie können sich eine Style bequeme Möglichkeit vorstellen, eine Reihe von Eigenschaftswerten auf mehrere Elemente anzuwenden. Sie können eine Formatvorlage auf jedes Element anwenden, das von FrameworkElement oder FrameworkContentElement abgeleitet ist, wie etwa einem Window oder einem Button.
Die am häufigsten verwendete Methode zum Definieren eines Stils ist die Deklaration als Ressource im Resources
Abschnitt in einer XAML-Datei. Da es sich bei Formatvorlagen um Ressourcen handelt, befolgen sie dieselben Bereichsregeln, die für alle Ressourcen gelten. Einfach ausgedrückt, wo Sie eine Formatvorlage deklarieren, wirkt sich darauf aus, wo die Formatvorlage angewendet werden kann. Wenn Sie z. B. die Formatvorlage im Stammelement der XAML-Datei der App-Definition deklarieren, kann die Formatvorlage an einer beliebigen Stelle in Ihrer App verwendet werden.
Der folgende XAML-Code deklariert z. B. zwei Formatvorlagen für ein TextBlock
, eine automatisch auf alle TextBlock
Elemente angewendet wird und eine andere, auf die explizit verwiesen werden muss.
<Window.Resources>
<!-- .... other 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>
<!--A Style that extends the previous TextBlock 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>
Nachfolgend sehen Sie ein Beispiel für die oben deklarierten Formatvorlagen.
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
Weitere Informationen finden Sie unter Erstellen einer Formatvorlage für ein Steuerelement.
ControlTemplates
In WPF definiert das ControlTemplate eines Steuerelements die Darstellung des Steuerelements. Sie können die Struktur und Darstellung eines Steuerelements ändern, indem Sie ein neues ControlTemplate Steuerelement definieren und einem Steuerelement zuweisen. In vielen Fällen bieten Vorlagen genügend Flexibilität, sodass Sie keine eigenen benutzerdefinierten Steuerelemente schreiben müssen.
Jedes Steuerelement verfügt über eine Standardvorlage, die der Control.Template-Eigenschaft zugewiesen ist. Die Vorlage verbindet die visuelle Darstellung des Steuerelements mit den Funktionen des Steuerelements. Da Sie eine Vorlage in XAML definieren, können Sie die Darstellung des Steuerelements ändern, ohne Code zu schreiben. Jede Vorlage wurde für ein spezifisches Steuerelement wie zum Beispiel ein Button entworfen.
Häufig deklarieren Sie eine Vorlage als Ressource im Resources
Abschnitt einer XAML-Datei. Wie bei allen Ressourcen gelten Bereichsregeln.
Steuerelementvorlagen sind deutlich aufwändiger als ein Stil. Dies liegt daran, dass die Kontrollvorlage das visuelle Erscheinungsbild des gesamten Kontrolls neu gestaltet, während ein Stil einfach Eigenschaftsänderungen am vorhandenen Kontroll vornimmt. Da die Vorlage eines Steuerelements jedoch durch Festlegen der Control.Template-Eigenschaft angewendet wird, können Sie einen Stil verwenden, um eine Vorlage zu definieren oder festlegen.
Designer ermöglichen es Ihnen in der Regel, eine Kopie einer vorhandenen Vorlage zu erstellen und sie zu ändern. Wählen Sie beispielsweise im Visual Studio WPF-Designer ein CheckBox
Steuerelement aus, und klicken Sie dann mit der rechten Maustaste, und wählen Sie " Vorlage>bearbeiten" aus. Dieser Befehl generiert eine Formatvorlage, die eine Vorlage definiert.
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual1}"/>
<Setter Property="Background" Value="{StaticResource OptionMark.Static.Background1}"/>
<Setter Property="BorderBrush" Value="{StaticResource OptionMark.Static.Border1}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="checkBoxBorder" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="1" Opacity="0" Stretch="None"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="2" Opacity="0"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="true">
<Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual1}"/>
<Setter Property="Padding" Value="4,-1,0,0"/>
... content removed to save space ...
Das Bearbeiten einer Kopie einer Vorlage ist eine hervorragende Möglichkeit, um zu erfahren, wie Vorlagen funktionieren. Anstatt eine neue leere Vorlage zu erstellen, ist es einfacher, eine Kopie zu bearbeiten und einige Aspekte der visuellen Präsentation zu ändern.
Ein Beispiel finden Sie unter Erstellen einer Vorlage für ein Steuerelement.
Vorlagenbindung
Möglicherweise haben Sie bemerkt, dass die im vorherigen Abschnitt definierte Vorlagenressource die TemplateBinding-Markuperweiterung verwendet. A TemplateBinding
ist eine optimierte Form einer Bindung für Vorlagenszenarien, analog zu einer mit {Binding RelativeSource={RelativeSource TemplatedParent}}
.
TemplateBinding
ist nützlich, um Teile der Vorlage an Eigenschaften des Steuerelements zu binden. Beispielsweise verfügt jedes Steuerelement über eine BorderThickness Eigenschaft. Verwenden Sie ein TemplateBinding
, um festzulegen, welches Element in der Vorlage von dieser Kontrolle betroffen ist.
ContentControl und ItemsControl
Wenn ein ContentPresenter im ControlTemplate eines ContentControl deklariert ist, wird ContentPresenter automatisch mit den ContentTemplate- und Content-Eigenschaften verknüpft. Ebenso wird eine ItemsPresenter, die sich in einem ControlTemplateItemsControl befindet, automatisch an die ItemTemplate- und Items-Eigenschaften gebunden.
DataTemplates
In dieser Beispiel-App gibt es ein ListBox Steuerelement, das an eine Liste von Fotos gebunden ist.
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
Dies ListBox sieht derzeit wie folgt aus.
Die meisten Steuerelemente weisen einen Inhaltstyp auf, und dieser Inhalt stammt häufig aus Daten, an die Sie binden. In diesem Beispiel sind die Daten die Liste der Fotos. In WPF verwenden Sie eine DataTemplate , um die visuelle Darstellung von Daten zu definieren. Im Grunde bestimmt das, was Sie in eine DataTemplate Datei einfügen, was die Daten in der gerenderten App aussehen.
In unserer Beispiel-App verfügt jedes benutzerdefinierte Photo
Objekt über eine Source
Eigenschaft vom Typ Zeichenfolge, die den Dateipfad des Bilds angibt. Derzeit werden die Fotoobjekte als Dateipfade angezeigt.
public class Photo
{
public Photo(string path)
{
Source = path;
}
public string Source { get; }
public override string ToString() => Source;
}
Public Class Photo
Sub New(ByVal path As String)
Source = path
End Sub
Public ReadOnly Property Source As String
Public Overrides Function ToString() As String
Return Source
End Function
End Class
Damit die Fotos als Bilder angezeigt werden, erstellen Sie eine DataTemplate als Ressource.
<Window.Resources>
<!-- .... other 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 Eigenschaft "DataType" ähnlich ist wie die Eigenschaft "TargetType" der Style. Wenn sich DataTemplate im Abschnitt 'Ressourcen' befindet, wird DataType angewendet, wenn Sie die x:Key
-Eigenschaft einem Typ zuweisen und DataTemplate weglassen, wann immer dieser Typ erscheint. Sie haben immer die Möglichkeit, DataTemplate mit einer x:Key
zuzuweisen und sie dann als StaticResource
festzulegen für Eigenschaften, die DataTemplate-Typen verwenden, wie zum Beispiel die ItemTemplate-Eigenschaft oder die ContentTemplate-Eigenschaft.
Im Wesentlichen definiert das DataTemplate im obigen Beispiel, dass, wenn ein Photo
Objekt vorhanden ist, es als Image innerhalb eines Border angezeigt werden soll.
DataTemplateDamit sieht unsere App nun wie folgt aus.
Das Daten templating-Modell bietet weitere Features. Wenn Sie beispielsweise Sammlungsdaten anzeigen, die andere Auflistungen mit einem Typ wie z. B. a HeaderedItemsControlMenu oder a TreeViewenthalten, gibt es die HierarchicalDataTemplate. Ein weiteres Datentemplating-Feature ist das DataTemplateSelector, mit dem Sie eine DataTemplate basierend auf benutzerdefinierter Logik auswählen können. Weitere Informationen finden Sie unter Übersicht über die Datenvorlagen, die eine eingehendere Diskussion der verschiedenen Datenvorlagen-Features bietet.
Auslöser
Ein Trigger legt Eigenschaften fest oder startet Aktionen, z. B. eine Animation, wenn sich ein Eigenschaftswert ändert oder wenn ein Ereignis ausgelöst wird.
Style, ControlTemplateund DataTemplate alle verfügen über eine Triggers
Eigenschaft, die eine Reihe von Triggern enthalten kann. Es gibt mehrere Arten von Triggern.
PropertyTriggers
Ein Trigger Wert, der Eigenschaftswerte festlegt oder Aktionen basierend auf dem Wert einer Eigenschaft startet, wird als Eigenschaftstrigger bezeichnet.
Um zu veranschaulichen, wie Eigenschaftentrigger verwendet werden, können Sie jede ListBoxItem teilweise transparent machen, es sei denn, sie ist ausgewählt. Die folgende Formatvorlage setzt den Opacity-Wert eines ListBoxItem auf 0.5
. Wenn die IsSelected-Eigenschaft jedoch true
ist, wird Opacity auf 1.0
gesetzt.
<Window.Resources>
<!-- .... other resources .... -->
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
In diesem Beispiel wird ein Eigenschaftswert mit einem Trigger festgelegt, aber beachten Sie, dass die Trigger Klasse auch die EnterActions und ExitActions Eigenschaften hat, die es einem Trigger ermöglichen, Aktionen auszuführen.
Beachten Sie, dass die MaxHeight-Eigenschaft von ListBoxItem auf 75
gesetzt ist. In der folgenden Abbildung ist das dritte Element das ausgewählte Element.
EventTriggers und Storyboards
Ein anderer Triggertyp ist der EventTrigger, der eine Reihe von Aktionen basierend auf dem Auftreten eines Ereignisses startet. Die folgenden EventTrigger Objekte geben beispielsweise an, dass, wenn der Mauszeiger ListBoxItem eintritt, die MaxHeight Eigenschaft in einen Wert von 90
über eine Dauer von 0.2
Sekunden animiert wird. Wenn die Maus vom Element weg bewegt wird, kehrt die Eigenschaft über einen Zeitraum von 1
sekunden zum ursprünglichen Wert zurück. Beachten Sie, dass es nicht erforderlich ist, einen To Wert für die MouseLeave Animation anzugeben. Dies liegt daran, dass die Animation den ursprünglichen Wert nachverfolgen kann.
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
<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>
</Style.Triggers>
Weitere Informationen finden Sie in der Übersicht über Storyboards.
In der folgenden Abbildung zeigt die Maus auf das dritte Element.
MultiTriggers, DataTriggers und MultiDataTriggers
Zusätzlich zu Trigger und EventTrigger, gibt es andere Arten von Triggern. MultiTrigger ermöglicht es Ihnen, Eigenschaftswerte basierend auf mehreren Bedingungen festzulegen. Sie verwenden DataTrigger und MultiDataTrigger wann die Eigenschaft Ihrer Bedingung datengebunden ist.
Visuelle Zustände
Steuerelemente befinden sich immer in einem bestimmten Zustand. Wenn die Maus beispielsweise über die Oberfläche eines Steuerelements bewegt wird, gilt das Steuerelement als in einem allgemeinen Zustand von MouseOver
. Ein Steuerelement ohne einen bestimmten Zustand gilt als im gemeinsamen Normal
Zustand. Staaten sind in Gruppen unterteilt, und die zuvor genannten Bundesstaaten sind Teil der Statusgruppe CommonStates
. Die meisten Steuerelemente verfügen über zwei Statusgruppen: CommonStates
und FocusStates
. Von jeder Statusgruppe, die auf ein Steuerelement angewendet wird, befindet sich ein Steuerelement immer in einem Zustand jeder Gruppe, wie zum Beispiel CommonStates.MouseOver
und FocusStates.Unfocused
. Ein Steuerelement kann sich jedoch nicht in zwei verschiedenen Zuständen innerhalb derselben Gruppe befinden, z. B. CommonStates.Normal
und CommonStates.Disabled
. Hier ist eine Tabelle mit Zuständen, die die meisten Steuerelemente erkennen und verwenden.
VisualState-Name | VisualStateGroup-Name | BESCHREIBUNG |
---|---|---|
Normal |
CommonStates |
Der Standardstatus. |
MouseOver |
CommonStates |
Der Mauszeiger wird über dem Steuerelement positioniert. |
Pressed |
CommonStates |
Das Steuerelement wird gedrückt. |
Disabled |
CommonStates |
Das Steuerelement ist deaktiviert. |
Focused |
FocusStates |
Der Fokus liegt auf dem Steuerelement. |
Unfocused |
FocusStates |
Der Fokus liegt nicht auf dem Steuerelement. |
Durch Definieren eines System.Windows.VisualStateManager Stammelements einer Steuerelementvorlage können Sie Animationen auslösen, wenn ein Steuerelement in einen bestimmten Zustand wechselt. Die VisualStateManager
deklariert, welche Kombinationen von VisualStateGroup und VisualState zu beobachten sind. Wenn das Steuerelement in einen überwachten Zustand wechselt, wird die durch VisualStateManager
definierte Animation gestartet.
Der folgende XAML-Code überwacht z. B. den CommonStates.MouseOver
Zustand, um die Füllfarbe des Elements mit dem Namen backgroundElement
zu animieren. Wenn das Steuerelement in den CommonStates.Normal
Zustand zurückkehrt, wird die Füllfarbe des benannten backgroundElement
Elements wiederhergestellt.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{TemplateBinding Background}"
Duration="0:0:0.3"/>
</VisualState>
<VisualState Name="MouseOver">
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Yellow"
Duration="0:0:0.3"/>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
Weitere Informationen zu Storyboards finden Sie unter Storyboards Overview.
Freigegebene Ressourcen und Themen
Eine typische WPF-App verfügt möglicherweise über mehrere UI-Ressourcen, die in der gesamten App angewendet werden. Insgesamt kann dieser Satz von Ressourcen als Thema für die App betrachtet werden. WPF bietet Unterstützung für die Bündelung von UI-Ressourcen als Thema mithilfe eines Ressourcenwörterbuchs, das in der ResourceDictionary Klasse gekapselt ist.
WPF-Designs werden mithilfe des Stil- und Vorlagenmechanismus definiert, den WPF zum Anpassen der visuellen Elemente verfügbar macht.
WPF-Designressourcen werden in eingebetteten Ressourcenwörterbüchern gespeichert. Diese Ressourcenwörterbücher müssen in eine signierte Assembly eingebettet werden und können entweder in dieselbe Assembly wie der Code selbst oder in eine parallele Assembly eingebettet werden. Für PresentationFramework.dllbefinden sich die Assemblies, die WPF-Steuerelemente enthalten, Themenressourcen in einer Reihe von nebeneinanderliegenden Assemblies.
Das Thema wird zum letzten Mittel, um nach dem Stil eines Elements zu suchen. In der Regel beginnt die Suche damit, dass der Elementbaum nach einer geeigneten Ressource durchsucht wird, dann wird in der App-Ressourcensammlung nachgeschaut und schließlich das System abgefragt. Dadurch haben App-Entwickler die Möglichkeit, den Stil für jedes Objekt auf Struktur- oder App-Ebene neu zu definieren, bevor es das Design erreicht.
Sie können Ressourcendateien als einzelne Dateien definieren, mit denen Sie ein Thema in mehreren Apps wiederverwenden können. Sie können auch austauschbare Designs erstellen, indem Sie mehrere Ressourcenwörterbücher definieren, die dieselben Ressourcentypen, aber unterschiedliche Werte bereitstellen. Das Neudefinieren dieser Stile oder anderer Ressourcen auf App-Ebene ist der empfohlene Ansatz zur Anpassung einer App.
Zum Freigeben einer Gruppe von Ressourcen, einschließlich Stilen und Vorlagen, in allen Apps können Sie eine XAML-Datei erstellen und einen Verweis ResourceDictionary auf eine shared.xaml
Datei definieren.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
Es ist die Freigabe von shared.xaml
, die selbst ein ResourceDictionary definiert, das einen Satz von Stil- und Pinselressourcen enthält und den Steuerelementen in einer App ein einheitliches Aussehen ermöglicht.
Weitere Informationen finden Sie unter zusammengeführten Ressourcenwörterbücher.
Wenn Sie ein Design für Ihr benutzerdefiniertes Steuerelement erstellen, lesen Sie den Abschnitt "Definieren von Ressourcen auf Designebene" der Übersicht über die Erstellung von Steuerelementen.
Siehe auch
.NET Desktop feedback