Freigeben über


Erstellen einer Vorlage für ein Steuerelement (WPF.NET)

Mit Windows Presentation Foundation (WPF) können Sie die visuelle Struktur und das Verhalten eines vorhandenen Steuerelements mit Ihrer eigenen wiederverwendbaren Vorlage anpassen. Vorlagen können global auf Ihre Anwendung, Fenster und Seiten oder direkt auf Steuerelemente angewendet werden. Die meisten Szenarien, in denen Sie ein neues Steuerelement erstellen müssen, können stattdessen durch das Erstellen einer neuen Vorlage für ein vorhandenes Steuerelement abgedeckt werden.

In diesem Artikel erfahren Sie, wie Sie ein neues ControlTemplate für das Button-Steuerelement erstellen.

Wann eine ControlTemplate erstellt werden soll

Steuerelemente weisen viele Eigenschaften auf, wie Background, Foreground und FontFamily. Diese Eigenschaften steuern unterschiedliche Aspekte der Darstellung des Steuerelements, aber die Änderungen, die Sie vornehmen können, indem Sie diese Eigenschaften festlegen, sind eingeschränkt. Beispielsweise können Sie die Foreground-Eigenschaft auf blau und FontStyle auf kursiv für ein CheckBox einstellen. Wenn Sie die Darstellung des Steuerelements über die Einstellung der anderen Eigenschaften des Steuerelements hinaus anpassen möchten, erstellen Sie eine ControlTemplate.

In den meisten Benutzeroberflächen hat eine Schaltfläche das gleiche allgemeine Erscheinungsbild: ein Rechteck mit einem Text. Wenn Sie eine abgerundete Schaltfläche erstellen möchten, können Sie ein neues Steuerelement erstellen, das von der Schaltfläche erbt, oder die Funktionalität der Schaltfläche neu erstellt. Darüber hinaus würde das neue Benutzersteuerelement das kreisförmige Visuelle bereitstellen.

Sie können das Erstellen neuer Steuerelemente vermeiden, indem Sie das visuelle Layout eines vorhandenen Steuerelements anpassen. Mit einer abgerundeten Schaltfläche erstellen Sie ein ControlTemplate mit dem gewünschten visuellen Layout.

Wenn Sie dagegen ein Steuerelement mit neuen Funktionen, verschiedenen Eigenschaften und neuen Einstellungen benötigen, erstellen Sie ein neues UserControl.

Voraussetzungen

Erstellen Sie eine neue WPF-Anwendung, und legen Sie in "MainWindow.xaml " (oder einem anderen Fenster Ihrer Wahl) die folgenden Eigenschaften für das <Window-Element> fest:

Eigentum Wert
Title Template Intro Sample
SizeToContent WidthAndHeight
MinWidth 250

Legen Sie den Inhalt des <Window-Elements> auf den folgenden XAML-Code fest:

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

Am Ende sollte die Datei "MainWindow.xaml " wie folgt aussehen:

<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>

Wenn Sie die Anwendung ausführen, sieht sie wie folgt aus:

WPF-Fenster mit zwei schaltflächen ohne Stil

Erstellen einer ControlTemplate

Die am häufigsten verwendete Methode zum Deklarieren eines ControlTemplate als Ressource ist im Abschnitt Resources einer XAML-Datei. Da Vorlagen Ressourcen sind, befolgen sie dieselben Bereichsregeln, die für alle Ressourcen gelten. Einfach ausgedrückt, wo Sie eine Vorlage deklarieren, wirkt sich darauf aus, wo die Vorlage angewendet werden kann. Wenn Sie beispielsweise die Vorlage im Stammelement Der XAML-Datei der Anwendungsdefinition deklarieren, kann die Vorlage an einer beliebigen Stelle in Ihrer Anwendung verwendet werden. Wenn Sie die Vorlage in einem Fenster definieren, können nur die Steuerelemente in diesem Fenster die Vorlage verwenden.

Fügen Sie zunächst der Window.Resources" ein Element hinzu:

<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>

Erstellen Sie eine neue <ControlTemplate> mit dem folgenden Eigenschaftensatz:

Eigentum Wert
x:Key- roundbutton
TargetType Button

Diese Steuerelementvorlage ist einfach:

  • ein Stammelement für das Steuerelement, ein Grid
  • ein Ellipse , um das abgerundete Aussehen der Schaltfläche zu zeichnen
  • ein ContentPresenter zur Anzeige des vom Benutzer angegebenen Schaltflächeninhalts
<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

Vorlagenbindung

Wenn Sie ein neues ControlTemplate erstellen, könnten Sie weiterhin die öffentlichen Eigenschaften verwenden, um das Aussehen des Controls zu ändern. Die TemplateBinding-Markuperweiterung bindet eine Eigenschaft eines Elements, das sich in ControlTemplate einer öffentlichen Eigenschaft befindet, die vom Steuerelement definiert wird. Wenn Sie ein TemplateBinding verwenden, aktivieren Sie Eigenschaften für das Steuerelement, um als Parameter für die Vorlage zu fungieren. Wenn eine Eigenschaft für ein Steuerelement festgelegt wird, wird dieser Wert an das Element übergeben, das die TemplateBinding-Eigenschaft enthält.

Ellipse

Beachten Sie, dass die Fill Eigenschaften und Stroke Eigenschaften des <Ellipse-Elements> an die Eigenschaften und Foreground Eigenschaften des Steuerelements Background gebunden sind.

Content-Präsentator

Der Vorlage wird auch ein <ContentPresenter-Element> hinzugefügt. Da diese Vorlage für eine Schaltfläche konzipiert ist, ziehen Sie in Betracht, dass die Schaltfläche von ContentControl erbt. Die Schaltfläche zeigt den Inhalt des Elements an. Sie können alles innerhalb der Schaltfläche festlegen, z. B. Nur-Text oder sogar ein anderes Steuerelement. Beides sind gültige Schaltflächen:

<Button>My Text</Button>

<!-- and -->

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

In beiden vorherigen Beispielen wird der Text und das Kontrollkästchen als Button.Content-Eigenschaft festgelegt. Was auch immer als Inhalt festgelegt ist, kann über einen <ContentPresenter> dargestellt werden, was die Vorlage tut.

Wenn ControlTemplate auf einen ContentControl-Typ angewendet wird, wie etwa ein Button, wird nach einer ContentPresenter im Elementbaum gesucht. Wenn ContentPresenter gefunden wird, bindet die Vorlage automatisch die Eigenschaft des Steuerelements Content an ContentPresenter.

Verwenden der Vorlage

Suchen Sie die Schaltflächen, die am Anfang dieses Artikels deklariert wurden.

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

Legen Sie die Eigenschaft der zweiten Schaltfläche Template auf die roundbutton Ressource fest:

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

Wenn Sie das Projekt ausführen und das Ergebnis betrachten, sehen Sie, dass die Schaltfläche einen abgerundeten Hintergrund aufweist.

WPF-Fenster mit einer ovalen Vorlageschaltfläche

Möglicherweise haben Sie bemerkt, dass die Schaltfläche kein Kreis ist, sondern schief ist. Aufgrund der Funktionsweise des <Ellipse-Elements> wird es immer erweitert, um den verfügbaren Platz auszufüllen. Gestalten Sie den Kreis einheitlich, indem Sie die Eigenschaften der Schaltfläche width und height auf denselben Wert ändern.

<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-Fenster mit einem kreisförmigen Vorlagenbutton

Hinzufügen eines Triggers

Obwohl eine Schaltfläche mit angewendeter Vorlage anders aussieht, verhält sie sich genauso wie jede andere Schaltfläche. Wenn Sie die Schaltfläche drücken, wird das Click Ereignis ausgelöst. Möglicherweise haben Sie jedoch bemerkt, dass sich die visuellen Elemente der Schaltfläche nicht ändern, wenn Sie mit der Maus über die Schaltfläche navigieren. Diese visuellen Interaktionen werden alle durch die Vorlage definiert.

Mit den dynamischen Ereignis- und Eigenschaftensystemen, die WPF bereitstellt, können Sie eine bestimmte Eigenschaft für einen Wert ansehen und dann die Vorlage bei Bedarf neu formatieren. In diesem Beispiel sehen Sie sich die Eigenschaft der Schaltfläche IsMouseOver an. Wenn sich die Maus über dem Steuerelement befindet, formatieren Sie die <Ellipse> mit einer neuen Farbe. Dieser Triggertyp wird als PropertyTrigger bezeichnet.

Damit dies funktioniert, müssen Sie der Ellipse< einen Namen hinzufügen, auf den> Sie verweisen können. Geben Sie ihm den Namen " backgroundElement".

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

Als Nächstes fügen Sie der Trigger-Auflistung eine neue hinzu. Der Trigger überwacht das IsMouseOver Ereignis für den Wert 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>

Fügen Sie als Nächstes einen <Setter> zum <Trigger> hinzu, der die Fill-Eigenschaft der <Ellipse> in eine neue Farbe ändert.

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

Führen Sie das Projekt aus. Beachten Sie, dass sich beim Bewegen der Maus über die Schaltfläche die Farbe der <Ellipse> ändert.

Maus bewegt sich über die WPF-Schaltfläche, um die Füllfarbe zu ändern

Verwenden eines VisualState-Elements

Visuelle Zustände werden durch ein Steuerelement definiert und ausgelöst. Wenn die Maus beispielsweise über dem Steuerelement verschoben wird, wird der CommonStates.MouseOver Zustand ausgelöst. Sie können Eigenschaftsänderungen basierend auf dem aktuellen Zustand des Steuerelements animieren. Im vorherigen Abschnitt wurde ein <PropertyTrigger> verwendet, um den Hintergrund der Schaltfläche zu AliceBlue zu ändern, wenn die Eigenschaft IsMouseOvertrue war. Erstellen Sie stattdessen einen visuellen Zustand, der die Änderung dieser Farbe animiert und einen reibungslosen Übergang ermöglicht. Weitere Informationen zu VisualStates finden Sie unter "Formatvorlagen und Vorlagen" in WPF.

Um den <PropertyTrigger> in einen animierten visuellen Zustand zu konvertieren, entfernen Sie zuerst das <ControlTemplate.Triggers-Element> aus Ihrer Vorlage.

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

Fügen Sie als Nächstes im <Grid-Root> der Steuerschablone das <VisualStateManager.VisualStateGroups-Element> mit einer <VisualStateGroup> für CommonStates hinzu. Definieren Sie zwei Zustände, Normal und 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>

Alle in einem <VisualState> definierten Animationen werden angewendet, wenn dieser Zustand ausgelöst wird. Erstellen Sie Animationen für jeden Zustand. Animationen werden innerhalb eines <Storyboardelements> platziert. Weitere Informationen zu Storyboards finden Sie unter Storyboards Overview.

  • Normal

    Dieser Zustand animiert die Ellipsefüllung und stellt sie in der Farbe des Steuerelements Background wieder her.

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

    Dieser Zustand animiert die Ellipsefarbe Background auf eine neue Farbe: Yellow.

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

Die <ControlTemplate> sollte nun wie folgt aussehen.

<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>

Führen Sie das Projekt aus. Beachten Sie, dass beim Bewegen der Maus über die Schaltfläche die Farbe der <Ellipse> animiert wird.

Maus bewegt sich über die WPF-Schaltfläche, um die Füllfarbe mit einem visuellen Zustand zu ändern

Nächste Schritte