Co jsou styly a šablony? (WPF .NET)
Styling a šablonování windows Presentation Foundation (WPF) odkazuje na sadu funkcí, které vývojářům a návrhářům umožňují vytvářet vizuálně atraktivní efekty a konzistentní vzhled svého produktu. Při přizpůsobení vzhledu aplikace chcete použít silný model stylů a šablon, který umožňuje údržbu a sdílení vzhledu v aplikacích i mezi aplikacemi. WPF poskytuje tento model.
Další funkcí modelu stylů WPF je oddělení prezentace a logiky. Návrháři můžou pracovat na vzhledu aplikace jenom pomocí XAML současně, kdy vývojáři pracují na programovací logice pomocí jazyka C# nebo Visual Basic.
Tento přehled se zaměřuje na styly a šablonování aspektů aplikace a neprobírá žádné koncepty datových vazeb. Informace o datové vazbě najdete v tématu Přehled datových vazeb.
Je důležité pochopit prostředky, které umožňují opakované použití stylů a šablon. Další informace o prostředcích najdete v tématu Přehled prostředků XAML.
Vzorek
Ukázkový kód uvedený v tomto přehledu vychází z jednoduché aplikace pro procházení fotek zobrazených na následujícím obrázku.
Tato jednoduchá ukázka fotek používá styly a šablony k vytvoření vizuálně atraktivního uživatelského prostředí. Ukázka má dva TextBlock prvky a ListBox ovládací prvek, který je svázán se seznamem obrázků.
Kompletní ukázku najdete v tématu Úvod do stylů a šablon.
Styly
Můžete si představit Style jako pohodlný způsob použití sady hodnot vlastností na více prvků. Styl můžete použít u libovolného prvku, který je odvozen nebo FrameworkElement FrameworkContentElement například Window Button.
Nejběžnější způsob, jak deklarovat styl, je jako prostředek v Resources
oddílu v souboru XAML. Vzhledem k tomu, že styly jsou prostředky, dodržují stejná pravidla oborů, která platí pro všechny prostředky. Jednoduše řečeno, kde deklarujete styl, má vliv na to, kde se styl dá použít. Pokud například deklarujete styl v kořenovém prvku souboru XAML definice aplikace, můžete styl použít kdekoli v aplikaci.
Například následující kód XAML deklaruje dva styly pro jeden TextBlock
automaticky použitý pro všechny TextBlock
prvky a druhý, který musí být explicitně odkazován.
<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>
Tady je příklad výše deklarovaných stylů.
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
Další informace naleznete v tématu Vytvoření stylu ovládacího prvku.
ControlTemplates
Ve WPF ControlTemplate definuje ovládací prvek vzhled ovládacího prvku. Strukturu a vzhled ovládacího prvku můžete změnit definováním nového ControlTemplate ovládacího prvku a jeho přiřazením k ovládacímu prvku. V mnoha případech vám šablony poskytují dostatečnou flexibilitu, abyste nemuseli psát vlastní ovládací prvky.
Každý ovládací prvek má výchozí šablonu přiřazenou k Control.Template vlastnost. Šablona spojuje vizuální prezentaci ovládacího prvku s možnostmi ovládacího prvku. Vzhledem k tomu, že definujete šablonu v XAML, můžete změnit vzhled ovládacího prvku bez psaní kódu. Každá šablona je určena pro určitý ovládací prvek, například Button.
Obvykle deklarujete šablonu jako prostředek v Resources
části souboru XAML. Stejně jako u všech prostředků platí pravidla oborů.
Šablony ovládacích prvků jsou mnohem více zapojené než styl. Důvodem je to, že šablona ovládacího prvku přepíše vzhled celého ovládacího prvku, zatímco styl jednoduše použije změny vlastností na existující ovládací prvek. Vzhledem k tomu, že se šablona ovládacího prvku použije nastavením vlastnosti Control.Template , můžete použít styl k definování nebo nastavení šablony.
Návrháři obecně umožňují vytvořit kopii existující šablony a upravit ji. Například v návrháři WPF sady Visual Studio vyberte CheckBox
ovládací prvek a potom klikněte pravým tlačítkem myši a vyberte Upravit šablonu>Vytvořit kopii. Tento příkaz vygeneruje styl, který definuje šablonu.
<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 ...
Úprava kopie šablony je skvělý způsob, jak se naučit, jak šablony fungují. Místo vytvoření nové prázdné šablony je jednodušší upravit kopii a změnit několik aspektů vizuální prezentace.
Příklad najdete v tématu Vytvoření šablony pro ovládací prvek.
TemplateBinding
Možná jste si všimli, že prostředek šablony definovaný v předchozí části používá Rozšíření značek TemplateBinding. A TemplateBinding
je optimalizovaná forma vazby pro scénáře šablony, podobně jako vazby vytvořené pomocí {Binding RelativeSource={RelativeSource TemplatedParent}}
. TemplateBinding
je užitečné pro vazby částí šablony s vlastnostmi ovládacího prvku. Každý ovládací prvek BorderThickness má například vlastnost. TemplateBinding
Použití ke správě prvku v šabloně je ovlivněn tímto nastavením ovládacího prvku.
ContentControl a ItemsControl
Pokud je deklarován ContentPresenter v ControlTemplate objektu ContentControl, ContentPresenter automaticky se sváže s vlastnostmi a Content vlastnostmiContentTemplate. Podobně se objektItemsPresenter, který je v objektuControlTemplate, ItemsControl automaticky sváže s vlastnostmi a Items vlastnostmiItemTemplate.
DataTemplates
V této ukázkové aplikaci je ListBox ovládací prvek, který je svázán se seznamem fotek.
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
V současné době to ListBox vypadá takto.
Většina ovládacích prvků má určitý typ obsahu a tento obsah často pochází z dat, ke kterým vytváříte vazbu. V této ukázce jsou data seznamem fotek. Ve WPF použijete DataTemplate k definování vizuální reprezentace dat. V podstatě to, co vložíte do určení DataTemplate , jak data vypadají v vykreslené aplikaci.
V naší ukázkové aplikaci má Source
každý vlastní Photo
objekt vlastnost typu řetězec, který určuje cestu k souboru obrázku. V současné době se objekty fotografií zobrazují jako cesty k souborům.
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
Aby se fotky zobrazovaly jako obrázky, vytvoříte jako DataTemplate prostředek.
<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>
Všimněte si, že DataType vlastnost je podobná TargetType vlastnosti Style. Pokud se nacházíte DataTemplate v oddílu prostředků, při zadání DataType vlastnosti typu a vynechání x:Key
, použije DataTemplate se při každém zobrazení daného typu. Vždy máte možnost přiřadit ho k objektu DataTemplate x:Key
a nastavit ho jako StaticResource
vlastnosti, které přebírají DataTemplate typy, jako ItemTemplate je například vlastnost nebo ContentTemplate vlastnost.
V podstatě výše DataTemplate uvedený příklad definuje, že pokaždé, když je Photo
objekt, by měl vypadat jako Image uvnitř .Border Díky tomu DataTemplateteď naše aplikace vypadá takto.
Model šablon dat poskytuje další funkce. Například pokud zobrazujete data shromažďování, která obsahují jiné kolekce pomocí HeaderedItemsControl typu, jako Menu je například nebo , TreeViewje HierarchicalDataTemplatetam . Další funkcí šablonování dat je DataTemplateSelectorfunkce , která umožňuje zvolit DataTemplate použití na základě vlastní logiky. Další informace najdete v tématu Přehled šablon dat, který poskytuje podrobnější diskuzi o různých funkcích šablon dat.
Aktivační události
Trigger nastaví vlastnosti nebo spustí akce, jako je animace, když se změní hodnota vlastnosti nebo při vyvolání události. Style, ControlTemplatea DataTemplate všechny mají Triggers
vlastnost, která může obsahovat sadu triggerů. Existuje několik typů triggerů.
PropertyTriggers
A Trigger , který nastavuje hodnoty vlastností nebo spouští akce na základě hodnoty vlastnosti, se nazývá aktivační událost vlastnosti.
Abyste si ukázali, jak používat triggery vlastností, můžete každou ListBoxItem částečně průhlednou, pokud není vybraná. Následující styl nastaví Opacity hodnotu ListBoxItem na 0.5
hodnotu . Pokud je true
však IsSelected vlastnost nastavena Opacity na 1.0
hodnotu .
<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>
Tento příklad používá Trigger k nastavení hodnoty vlastnosti, ale všimněte si, že Trigger třída má EnterActions také vlastnosti, ExitActions které umožňují triggeru provádět akce.
Všimněte si, že MaxHeight vlastnost objektu je nastavena ListBoxItem na 75
hodnotu . Na následujícím obrázku je třetí položka vybranou položkou.
EventTriggery a scénáře
Dalším typem triggeru EventTriggerje trigger , který spouští sadu akcí na základě výskytu události. Například následující EventTrigger objekty určují, že když ukazatel myši zadá ListBoxItem, MaxHeight vlastnost animace na hodnotu 90
za 0.2
druhé období. Když se myš přesune od položky, vrátí se vlastnost k původní hodnotě za období sekundy 1
. Všimněte si, že není nutné zadat To hodnotu animace MouseLeave . Je to proto, že animace dokáže sledovat původní hodnotu.
<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>
Další informace najdete v přehledu scénářů.
Na následujícím obrázku myš ukazuje na třetí položku.
MultiTriggery, DataTriggery a MultiDataTriggery
Kromě Trigger a EventTriggerexistují i další typy aktivačních událostí. MultiTrigger umožňuje nastavit hodnoty vlastností na základě více podmínek. Použijete DataTrigger a MultiDataTrigger kdy je vlastnost podmínky svázaná s daty.
Stavy vizuálů
Ovládací prvky jsou vždy v určitém stavu. Například když se myš pohybuje nad povrchem ovládacího prvku, považuje se ovládací prvek za společný stav MouseOver
. Řízení bez konkrétního stavu se považuje za společné Normal
. Státy jsou rozděleny do skupin a dříve uvedené stavy jsou součástí skupiny CommonStates
států . Většina ovládacích prvků má dvě skupiny stavů: CommonStates
a FocusStates
. Z každé skupiny stavů použité na ovládací prvek je ovládací prvek vždy v jednom stavu každé skupiny, například CommonStates.MouseOver
a FocusStates.Unfocused
. Ovládací prvek však nemůže být ve dvou různých stavech ve stejné skupině, například CommonStates.Normal
a CommonStates.Disabled
. Tady je tabulka stavů, které většina ovládacích prvků rozpozná a používá.
Název visualstate | Název skupiny VisualStateGroup | Popis |
---|---|---|
Normal |
CommonStates |
Výchozí stav. |
MouseOver |
CommonStates |
Ukazatel myši se umístí nad ovládací prvek. |
Pressed |
CommonStates |
Ovládací prvek se stiskne. |
Disabled |
CommonStates |
Ovládací prvek je zakázaný. |
Focused |
FocusStates |
Ovládací prvek má fokus. |
Unfocused |
FocusStates |
Ovládací prvek nemá fokus. |
System.Windows.VisualStateManager Definováním kořenového prvku šablony ovládacího prvku můžete aktivovat animace, když ovládací prvek vstoupí do určitého stavu. Deklarace VisualStateManager
, které kombinace VisualStateGroup a VisualState sledování. Když ovládací prvek přejde do sledovaného stavu, animace definovaná objektem je spuštěna VisualStateManager
.
Například následující kód XAML sleduje CommonStates.MouseOver
stav animace barvy výplně prvku s názvem backgroundElement
. Když se ovládací prvek vrátí do CommonStates.Normal
stavu, obnoví se barva výplně pojmenovaného backgroundElement
prvku.
<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>
...
Další informace o scénářích najdete v tématu Přehled scénářů.
Sdílené prostředky a motivy
Typická aplikace WPF může mít více prostředků uživatelského rozhraní, které se použijí v celé aplikaci. Společně lze tuto sadu prostředků považovat za motiv aplikace. WPF poskytuje podporu pro balení prostředků uživatelského rozhraní jako motiv pomocí slovníku prostředků, který je zapouzdřen jako ResourceDictionary třída.
Motivy WPF jsou definovány pomocí mechanismu stylů a šablon, který WPF zveřejňuje pro přizpůsobení vizuálů libovolného prvku.
Prostředky motivu WPF se ukládají do vložených slovníků prostředků. Tyto slovníky prostředků musí být vloženy do podepsaného sestavení a mohou být vloženy do stejného sestavení jako samotný kód nebo do souběžného sestavení. Pro PresentationFramework.dll sestavení, které obsahuje ovládací prvky WPF, jsou prostředky motivu v řadě souběžných sestavení.
Motiv se stane posledním místem, kde se má hledat styl prvku. Hledání obvykle začíná procházením stromu prvků, který hledá vhodný prostředek, pak se podívá do kolekce prostředků aplikace a nakonec se do systému dotazuje. Vývojáři aplikací tak můžou před dosažením motivu předefinovat styl libovolného objektu na úrovni stromu nebo aplikace.
Slovníky prostředků můžete definovat jako jednotlivé soubory, které umožňují opakovaně používat motiv napříč více aplikacemi. Můžete také vytvořit prohozené motivy definováním více slovníků prostředků, které poskytují stejné typy prostředků, ale s různými hodnotami. Předefinování těchto stylů nebo jiných prostředků na úrovni aplikace je doporučeným přístupem pro úpravu aplikace.
Pokud chcete sdílet sadu prostředků, včetně stylů a šablon, napříč aplikacemi, můžete vytvořit soubor XAML a definovat ResourceDictionary soubor, který obsahuje odkaz na shared.xaml
soubor.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
Jedná se o shared.xaml
sdílení , který sám definuje ResourceDictionary , která obsahuje sadu stylů a prostředků štětců, která umožňuje ovládacím prvkům v aplikaci mít konzistentní vzhled.
Další informace najdete v tématu Slovníky sloučených prostředků.
Pokud vytváříte motiv pro vlastní ovládací prvek, přečtěte si část Definování prostředků na úrovni motivu v přehledu vytváření ovládacích prvků.
Viz také
.NET Desktop feedback