Creare un modello per un controllo
Con Windows Presentation Foundation (WPF), è possibile personalizzare la struttura visiva e il comportamento di un controllo esistente con il proprio modello riutilizzabile. I modelli possono essere applicati a livello globale all'applicazione, alle finestre e alle pagine o direttamente ai controlli. La maggior parte degli scenari che richiedono la creazione di un nuovo controllo può essere coperta dalla creazione di un nuovo modello per un controllo esistente.
In questo articolo esplorerai la creazione di un nuovo ControlTemplate per il controllo Button.
Quando creare un ControlTemplate
I controlli hanno molte proprietà, ad esempio Background, Foregrounde FontFamily. Queste proprietà controllano aspetti diversi dell'aspetto del controllo, ma le modifiche che è possibile apportare impostando queste proprietà sono limitate. Ad esempio, è possibile impostare la proprietà Foreground su blu e FontStyle in corsivo su un CheckBox. Quando si desidera personalizzare l'aspetto del controllo oltre a quanto è possibile fare impostando le altre proprietà del controllo, si può creare un ControlTemplate.
Nella maggior parte delle interfacce utente, un pulsante ha lo stesso aspetto generale: un rettangolo con un testo. Se si desidera creare un pulsante arrotondato, è possibile creare un nuovo controllo che eredita dal pulsante o ricreare la funzionalità del pulsante. Inoltre, il nuovo controllo utente offrirà la visualizzazione circolare.
È possibile evitare di creare nuovi controlli personalizzando il layout visivo di un controllo esistente. Con un pulsante arrotondato, si crea un ControlTemplate con il layout visivo desiderato.
D'altra parte, se è necessario un controllo con nuove funzionalità, proprietà diverse e nuove impostazioni, è necessario creare un nuovo UserControl.
Prerequisiti
Creare una nuova applicazione WPF e in MainWindow.xaml (o un'altra finestra a scelta) impostare le seguenti proprietà sull'elemento <Window>:
Proprietà | Valore |
---|---|
Title | Template Intro Sample |
SizeToContent | WidthAndHeight |
MinWidth | 250 |
Impostare il contenuto della finestra <dell'elemento> sul seguente XAML:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
Alla fine, il file MainWindow.xaml
<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>
Se si esegue l'applicazione, l'applicazione avrà un aspetto simile al seguente:
Creare un ControlTemplate
Il modo più comune per dichiarare un ControlTemplate è una risorsa nella sezione Resources
in un file XAML. Poiché i modelli sono risorse, obbediscono alle stesse regole di ambito applicabili a tutte le risorse. In parole povere, il punto in cui si dichiara un modello influisce su dove il modello può essere applicato. Ad esempio, se dichiari il modello nell'elemento radice del file XAML di definizione dell'applicazione, il modello può essere usato in qualsiasi punto dell'applicazione. Se si definisce il modello in una finestra, solo i controlli in tale finestra possono usare il modello.
Per iniziare, aggiungere un elemento Window.Resources
al file MainWindow.xaml:
<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>
Creare un nuovo <ControlTemplate> con le proprietà seguenti impostate:
Proprietà | Valore |
---|---|
x:Key | roundbutton |
TargetType | Button |
Questo modello di controllo sarà semplice:
- un elemento radice per il controllo, un Grid
- un Ellipse per disegnare l'aspetto arrotondato del pulsante
- un ContentPresenter per visualizzare il contenuto del pulsante specificato dall'utente
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
TemplateBinding
Quando si crea un nuovo ControlTemplate, è comunque possibile usare le proprietà pubbliche per modificare l'aspetto del controllo. L'estensione di markup TemplateBinding associa una proprietà di un elemento incluso nel ControlTemplate a una proprietà pubblica definita dal controllo . Quando si usa un TemplateBinding, si abilitano le proprietà del controllo affinché agiscano come parametri del modello. Ovvero, quando viene impostata una proprietà di un controllo, tale valore viene passato all'elemento con il TemplateBinding su di esso.
Ellisse
Si noti che le proprietà
Presentatore di Contenuti
Viene aggiunto al modello un elemento <ContentPresenter>. Poiché questo modello è progettato per un pulsante, si tenga presente che il pulsante eredita da ContentControl. Il pulsante presenta il contenuto dell'elemento. È possibile impostare qualsiasi elemento all'interno del pulsante, ad esempio testo normale o anche un altro controllo. Entrambi i pulsanti seguenti sono validi:
<Button>My Text</Button>
<!-- and -->
<Button>
<CheckBox>Checkbox in a button</CheckBox>
</Button>
In entrambi gli esempi precedenti il testo e la casella di controllo vengono impostati come proprietà Button.Content. Qualsiasi elemento impostato come contenuto può essere presentato tramite un <ContentPresenter>, che è ciò che fa il modello.
Se il ControlTemplate viene applicato a un tipo di ContentControl, ad esempio un Button
, viene eseguita la ricerca di un ContentPresenter nell'albero degli elementi. Se viene trovato il ContentPresenter
, il modello associa automaticamente la proprietà Content del controllo all'ContentPresenter
.
Usare il modello
Trovare i pulsanti dichiarati all'inizio di questo articolo.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
Impostare la proprietà Template del secondo pulsante sulla risorsa roundbutton
:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>
Se si esegue il progetto e si esamina il risultato, si noterà che il pulsante ha uno sfondo arrotondato.
Potresti aver notato che il pulsante non è un cerchio, ma è asimmetrico. A causa del modo in cui funziona l'elemento <Ellipse>, si espande sempre per riempire lo spazio disponibile. Rendere uniforme il cerchio modificando le proprietà width e height del pulsante allo stesso valore:
<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>
Aggiungere un trigger
Anche se un pulsante con un modello applicato ha un aspetto diverso, si comporta come qualsiasi altro pulsante. Se premi il pulsante, l'evento Click si attiva. Tuttavia, potresti aver notato che quando sposti il mouse sul pulsante, l'aspetto del pulsante non cambia. Queste interazioni visive sono tutte definite dal modello.
Con i sistemi dinamici di eventi e proprietà forniti da WPF, è possibile monitorare una proprietà specifica per un determinato valore e quindi rimodellare il template quando appropriato. In questo esempio si osserverà la proprietà IsMouseOver del pulsante. Quando il mouse si trova sul controllo, dare uno stile al <Ellipse> con un nuovo colore. Questo tipo di trigger è noto come PropertyTrigger.
Affinché funzioni, è necessario aggiungere un nome all'<Ellipse> a cui è possibile fare riferimento. Dai il nome di backgroundElement.
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
Quindi, aggiungi un nuovo Trigger alla raccolta ControlTemplate.Triggers. Il trigger osserverà l'evento IsMouseOver
per il valore 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>
Aggiungi quindi un Setter <> al Trigger <> che cambia la proprietà Fill dell'Ellipse <> in un nuovo colore.
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
Eseguire il progetto. Si noti che quando si sposta il mouse sul pulsante, cambia il colore dell'<Ellisse>.
Usare un VisualState
Gli stati di visualizzazione vengono definiti e attivati da un controllo . Ad esempio, quando il mouse viene spostato sopra il controllo, viene attivato lo stato CommonStates.MouseOver
. È possibile animare le modifiche delle proprietà in base allo stato corrente del controllo. Nella sezione precedente, un <PropertyTrigger> è stato usato per cambiare il colore del testo del pulsante a AliceBlue
quando la proprietà IsMouseOver
era true
. Creare invece uno stato visivo che anima il cambiamento del colore, fornendo una transizione uniforme. Per ulteriori informazioni su VisualStates, vedere Stili e modelli in WPF.
Per convertire il <PropertyTrigger> in uno stato di visualizzazione animato, rimuovere prima di tutto l'elemento <ControlTemplate.Triggers> dal modello.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Nel <Grid> radice del modello di controllo aggiungere quindi l'elemento <VisualStateManager.VisualStateGroups> con un <VisualStateGroup> per CommonStates
. Definire due stati, Normal
e 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>
Tutte le animazioni definite in un <VisualState> vengono applicate quando viene attivato tale stato. Creare animazioni per ogni stato. Le animazioni vengono inserite all'interno di un elemento <Storyboard>. Per ulteriori informazioni sugli storyboard, vedere Panoramica di Storyboards.
Normale
Questo stato anima il riempimento dell'ellisse, ripristinandolo al colore
Background
del controllo.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>
passaggio del mouse
Questo stato anima il colore dell'ellisse
Background
a un nuovo colore:Yellow
.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
Il <ControlTemplate> dovrebbe ora essere simile al seguente.
<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>
Eseguire il progetto. Si noti che quando si sposta il mouse sul pulsante, il colore dell'Ellisse <> si anima.
Passaggi successivi
- stili e modelli di in WPF
- Panoramica delle risorse XAML
.NET Desktop feedback