Vytvoření šablony pro ovládací prvek (WPF.NET)

Pomocí windows Presentation Foundation (WPF) můžete přizpůsobit vizuální strukturu a chování existujícího ovládacího prvku pomocí vlastní opakovaně použitelné šablony. Šablony se dají použít globálně na vaši aplikaci, okna a stránky nebo přímo na ovládací prvky. Většina scénářů, které vyžadují, abyste vytvořili nový ovládací prvek, je možné pokrýt vytvořením nové šablony pro existující ovládací prvek.

Důležité

Dokumentace k desktopové příručce pro .NET 7 a .NET 6 se právě připravuje.

V tomto článku prozkoumáte vytvoření nového ControlTemplateButton ovládacího prvku.

Kdy vytvořit ControlTemplate

Ovládací prvky mají mnoho vlastností, například Background, Foregrounda FontFamily. Tyto vlastnosti řídí různé aspekty vzhledu ovládacího prvku, ale změny, které můžete provést nastavením těchto vlastností, jsou omezené. Můžete například nastavit Foreground vlastnost na modrou a FontStyle kurzívu na .CheckBox Pokud chcete přizpůsobit vzhled ovládacího prvku nad rámec toho, co nastavení ostatních vlastností ovládacího prvku může udělat, vytvoříte .ControlTemplate

Ve většiněuživatelských Pokud chcete vytvořit zaokrouhlené tlačítko, můžete vytvořit nový ovládací prvek, který dědí z tlačítka nebo znovu vytvoří funkce tlačítka. Nový uživatelský ovládací prvek by navíc poskytoval kruhový vizuál.

Vytváření nových ovládacích prvků můžete zabránit přizpůsobením rozložení vizuálu existujícího ovládacího prvku. Pomocí zaobleného tlačítka vytvoříte ControlTemplate požadované rozložení vizuálu.

Na druhou stranu, pokud potřebujete ovládací prvek s novými funkcemi, různými vlastnostmi a novými nastaveními, vytvoříte novou UserControl.

Předpoklady

Vytvořte novou aplikaci WPF a v mainWindow.xaml (nebo jiném okně podle vašeho výběru) nastavte následující vlastnosti elementu< Window>:

Vlastnost Value
Title Template Intro Sample
SizeToContent WidthAndHeight
MinWidth 250

Nastavte obsah elementu <Window> na následující XAML:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button>Button 2</Button>
</StackPanel>

Na konci by měl soubor MainWindow.xaml vypadat nějak takto:

<Window x:Class="IntroToStylingAndTemplating.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:IntroToStylingAndTemplating"
        mc:Ignorable="d"
        Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
    <StackPanel Margin="10">
        <Label>Unstyled Button</Label>
        <Button>Button 1</Button>
        <Label>Rounded Button</Label>
        <Button>Button 2</Button>
    </StackPanel>
</Window>

Pokud aplikaci spustíte, vypadá takto:

WPF window with two unstyled buttons

Vytvoření ControlTemplate

Nejběžnější způsob deklarace je ControlTemplate jako prostředek v Resources oddílu v souboru XAML. Vzhledem k tomu, že šablony jsou prostředky, dodržují stejná pravidla oborů, která platí pro všechny prostředky. Jednoduše řečeno, kde deklarujete šablonu, má vliv na to, kde lze šablonu použít. Pokud například deklarujete šablonu v kořenovém prvku souboru XAML definice vaší aplikace, můžete šablonu použít kdekoli ve vaší aplikaci. Pokud šablonu definujete v okně, můžou šablonu používat jenom ovládací prvky v daném okně.

Začněte tím, že do souboru MainWindow.xaml přidáte Window.Resourceselement:

<Window x:Class="IntroToStylingAndTemplating.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:IntroToStylingAndTemplating"
        mc:Ignorable="d"
        Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
    <Window.Resources>
        
    </Window.Resources>
    <StackPanel Margin="10">
        <Label>Unstyled Button</Label>
        <Button>Button 1</Button>
        <Label>Rounded Button</Label>
        <Button>Button 2</Button>
    </StackPanel>
</Window>

Vytvořte nový <ControlTemplate> s následující sadou vlastností:

Vlastnost Value
x:Key roundbutton
TargetType Button

Tato šablona ovládacího prvku bude jednoduchá:

  • kořenový prvek pro ovládací prvek, a Grid
  • a Ellipse nakreslit zaokrouhlený vzhled tlačítka
  • zobrazení ContentPresenter obsahu tlačítka zadaného uživatelem
<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

TemplateBinding

Při vytváření nového ControlTemplateobjektu může být stále vhodné použít veřejné vlastnosti ke změně vzhledu ovládacího prvku. TemplateBinding rozšíření značek vytvoří vazbu vlastnosti elementu, který je ve ControlTemplate veřejné vlastnosti, která je definována ovládacím prvkem. Při použití TemplateBinding povolíte vlastnosti ovládacího prvku, aby fungovaly jako parametry šablony. To znamená, že když je vlastnost ovládacího prvku nastavena, tato hodnota je předána elementu, který má TemplateBinding na něm.

Elipsa

Všimněte si, že Fill vlastnosti elementu Stroke<Ellipse> jsou svázány s vlastnostmi a Background vlastnostmi ovládacího prvku.Foreground

Contentpresenter

Do šablony se také přidá element ContentPresenter>.< Vzhledem k tomu, že tato šablona je určena pro tlačítko, vezměte v úvahu, že tlačítko dědí z ContentControl. Tlačítko zobrazí obsah prvku. Můžete nastavit cokoli uvnitř tlačítka, například prostý text nebo dokonce jiný ovládací prvek. Obě následující tlačítka jsou platná:

<Button>My Text</Button>

<!-- and -->

<Button>
    <CheckBox>Checkbox in a button</CheckBox>
</Button>

V obou předchozích příkladech je text a zaškrtávací políčko nastaveny jako Button.Content vlastnost. To, co je nastavené jako obsah, se dá prezentovat prostřednictvím <ContentPresenteru>, což je to, co šablona dělá.

ControlTemplate Pokud je použit pro ContentControl typ, například Button, je ContentPresenter vyhledána ve stromu elementu. Pokud je nalezena ContentPresenter , šablona automaticky vytvoří vazbu vlastnosti ovládacího prvku Content na ContentPresenterhodnotu .

Použít šablonu

Najděte tlačítka deklarovaná na začátku tohoto článku.

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button>Button 2</Button>
</StackPanel>

Nastavte vlastnost druhého tlačítka Template na roundbutton prostředek:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>

Pokud projekt spustíte a podíváte se na výsledek, uvidíte, že tlačítko má zaoblené pozadí.

WPF window with one template oval button

Možná jste si všimli, že tlačítko není kruh, ale je zkosený. Vzhledem ke způsobu, jakým <funguje prvek Ellipse> , se vždy rozšiřuje, aby vyplnil dostupné místo. Změňte hodnotu tlačítka width a height vlastností na stejnou hodnotu, aby byl kruh jednotný:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>

WPF window with one template circular button

Přidání triggeru

I když tlačítko s použitou šablonou vypadá jinak, chová se stejně jako jakékoli jiné tlačítko. Pokud stisknete tlačítko, událost se Click aktivuje. Možná jste si ale všimli, že když na tlačítko přesunete myš, vizuály tlačítka se nezmění. Tyto interakce vizuálů jsou všechny definované šablonou.

S dynamickými systémy událostí a vlastností, které WPF poskytuje, můžete sledovat konkrétní vlastnost pro hodnotu a pak šablonu podle potřeby změnit. V tomto příkladu budete sledovat vlastnost tlačítka IsMouseOver . Když je myš nad ovládacím prvku, styl <elipsa> s novou barvou. Tento typ triggeru se označuje jako PropertyTrigger.

Aby to fungovalo, budete muset přidat název do <elipsy> , na kterou můžete odkazovat. Pojmenujte ho backgroundElement.

<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />

Dále přidejte novou Trigger do kolekce ControlTemplate.Triggers . Trigger bude sledovat IsMouseOver událost pro hodnotu true.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="true">

        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Dále přidejte setter> do triggeru><, který změní vlastnost Výplň elipsy><na novou barvu.<

<Trigger Property="IsMouseOver" Value="true">
    <Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>

Spustit projekt. Všimněte si, že když přesunete myš nad tlačítko, barva <elipsy> se změní.

mouse moves over WPF button to change the fill color

Použití visualstate

Vizuální stavy jsou definovány a aktivovány ovládacím prvek. Například když se myš přesune nad ovládací prvek, CommonStates.MouseOver stav se aktivuje. Změny vlastností můžete animovat na základě aktuálního stavu ovládacího prvku. V předchozí části byl <propertyTrigger> použit ke změně pozadí tlačítka na AliceBlue kdy IsMouseOver byla truevlastnost . Místo toho vytvořte vizuální stav, který animuje změnu této barvy a poskytuje hladký přechod. Další informace o VisualStates naleznete v tématu Styly a šablony WPF.

Chcete-li převést PropertyTrigger> do animovaného vizuálního stavu, nejprve odeberte< ControlTemplate.Triggers element z šablony>.<

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

Dále v kořenovém adresáři mřížky> šablony ovládacího prvku přidejte <VisualStateManager.VisualStateGroups> element s< VisualStateGroup> pro .CommonStates< Definujte dva stavy Normal a MouseOver.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                </VisualState>
                <VisualState Name="MouseOver">
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

Všechny animace definované v jazyce <VisualState> se použijí při aktivaci tohoto stavu. Vytváření animací pro každý stav Animace se vloží do elementu <Storyboard> . Další informace o scénářích najdete v tématu Přehled scénářů.

  • Normální

    Tento stav animuje tři tečky a obnoví ji na barvu ovládacího prvku Background .

    <Storyboard>
        <ColorAnimation Storyboard.TargetName="backgroundElement" 
            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
            To="{TemplateBinding Background}"
            Duration="0:0:0.3"/>
    </Storyboard>
    
  • Mouseover

    Tento stav animuje barvu tří teček Background na novou barvu: Yellow.

    <Storyboard>
        <ColorAnimation Storyboard.TargetName="backgroundElement" 
            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
            To="Yellow" 
            Duration="0:0:0.3"/>
    </Storyboard>
    

Ovládací prvek <ControlTemplate> by teď měl vypadat takto.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="backgroundElement" 
                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                            To="{TemplateBinding Background}"
                            Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
                <VisualState Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="backgroundElement" 
                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
                            To="Yellow" 
                            Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

Spustit projekt. Všimněte si, že když na tlačítko přesunete myš, barva <elipsy> animuje.

mouse moves over WPF button to change the fill color with a visual state

Další kroky