Markieren Sie das Kontrollkästchen Englisch, um die englische Version dieses Artikels anzuzeigen. Sie können den englischen Text auch in einem Popup-Fenster einblenden, indem Sie den Mauszeiger über den Text bewegen.
Übersetzung
Englisch

Anpassen der Darstellung eines vorhandenen Steuerelements durch Erstellen einer ControlTemplate

.NET Framework (current version)
 

Veröffentlicht: Juni 2016

Eine ControlTemplate gibt die visuelle Struktur und das visuelle Verhalten eines Steuerelements an. Sie können die Darstellung eines Steuerelements anpassen, indem Sie diesem eine neue ControlTemplate zuweisen. Beim Erstellen einer ControlTemplate ersetzen Sie die Darstellung eines vorhandenen Steuerelements, ohne dessen Funktionalität zu ändern. Beispielsweise können Sie festlegen, dass die Schaltflächen rund und nicht in der quadratischen Standardform angezeigt werden, mit den Schaltflächen wird jedoch trotzdem das jeweilige Click-Ereignis ausgelöst.

In diesem Thema werden die verschiedenen Teile einer ControlTemplate erklärt, das Erstellen einer einfachen ControlTemplate für einen Button wird veranschaulicht, und zudem wird erläutert, wie der Steuerelementvertrag eines Steuerelements interpretiert wird, sodass Sie dessen Darstellung anpassen können. Da Sie eine ControlTemplate in XAML erstellen, können Sie die Darstellung eines Steuerelements ändern, ohne Code schreiben zu müssen. Sie können einen Designer, z. B. Microsoft Expression Blend verwenden, um benutzerdefinierte Steuerelementvorlagen zu erstellen. Dieses Thema zeigt Beispiele in der XAML an, die die Darstellung einer Button anpassen. Am Ende des Themas wird das vollständige Beispiel aufgeführt. Weitere Informationen zum Verwenden von Expression Blend finden Sie unter Formatieren eines Steuerelements, das Vorlagen unterstützt.

Die folgenden Abbildungen zeigen eine Button, die die ControlTemplate verwendet, die in diesem Thema erstellt wird.

Schaltfläche mit einer benutzerdefinierten Steuerelementvorlage.

Eine Schaltfläche, die eine benutzerdefinierte Steuerelementvorlage verwendet

Schaltfläche mit einem roten Rahmen.

Eine Schaltfläche, die eine benutzerdefinierte Steuerelementvorlage verwendet und auf der sich der Mauszeiger befindet

In diesem Thema wird davon ausgegangen, dass Sie wissen, wie Steuerelemente und Formate erstellt und verwendet werden, wie unter Steuerelemente erläutert. Die in diesem Thema erläuterten Begriffe gelten für Elemente, die von der UserControl-Klasse ergeben, mit Ausnahme von Control. Eine ControlTemplate kann auf ein UserControl nicht angewendet werden.

Steuerelemente besitzen zahlreiche Eigenschaften, z. B. Background, Foreground, und FontFamily, die Sie festlegen können, um andere Aspekte der Steuerelementdarstellung anzugeben, jedoch sind die Änderungen, die Sie durch Festlegen dieser Eigenschaften vornehmen können, beschränkt. Zum Beispiel können Sie für eine CheckBox die Foreground-Eigenschaft auf blau und FontStyle auf kursiv festlegen.

Ohne die Möglichkeit, für Steuerelemente eine neue ControlTemplate zu erstellen, würden alle Steuerelemente in jeder WPF-basierten Anwendung die gleiche allgemeine Darstellung aufweisen. Dies würde das Erstellen von Anwendungen mit benutzerdefiniertem Aussehen und Verhalten stark einschränken. Standardmäßig besitzt jede CheckBox ähnliche Merkmale. Beispielsweise befindet sich der Inhalt der CheckBox stets rechts vom Auswahlindikator, und das Häkchen wird immer für die Angabe verwendet, dass die CheckBox aktiviert ist.

Eine ControlTemplate erstellen Sie, wenn Sie die Darstellung des Steuerelements in einem Grad anpassen möchten, der über das Festlegen der anderen Steuerelementeigenschaften hinaus geht. Im Beispiel mit der CheckBox wird angenommen, dass der Inhalt des Kontrollkästchens über dem Auswahlindikator angezeigt werden soll, und mit einem X angegeben werden soll, dass die CheckBox aktiviert ist. Sie geben diese Änderungen in der ControlTemplate des CheckBox an.

Die folgende Abbildung zeigt ein CheckBox, das eine Standard- ControlTemplate verwendet.

Kontrollkästchen mit der Standardsteuerelementvorlage.

Ein Kontrollkästchen, das die Standardsteuerelementvorlage verwendet

Die folgende Abbildung zeigt ein CheckBox, das eine benutzerdefinierte ControlTemplate verwendet, um den Inhalt des CheckBox über dem Auswahlindikator zu platzieren, und ein X anzeigt, wenn die CheckBox ausgewählt wird.

Kontrollkästchen mit einer benutzerdefinierten Steuerelementvorlage.

Ein Kontrollkästchen, das eine benutzerdefinierte Steuerelementvorlage verwendet

Die ControlTemplate für die CheckBox in diesem Beispiel ist relativ komplex, deshalb wird in diesem Thema ein einfacheres Beispiel zum Erstellen einer ControlTemplate für einen Button verwendet.

In WPF besteht ein Steuerelement häufig aus zusammengesetzten FrameworkElement-Objekten. Wenn Sie eine ControlTemplate erstellen, kombinieren Sie FrameworkElement-Objekte, um ein einzelnes Steuerelement zu erstellen. Eine ControlTemplate darf nur ein FrameworkElement als Stammelement besitzen. Das Stammelement enthält normalerweise weitere FrameworkElement-Objekte. Die Kombination der Objekte bestimmt die visuelle Struktur des Steuerelements.

Im folgenden Beispiel wird eine benutzerdefinierte ControlTemplate für den Button erstellt. Die ControlTemplate bestimmt die visuelle Struktur des Button. In diesem Beispiel wird die Darstellung der Schaltfläche nicht geändert, wenn Sie den Mauszeiger darüber platzieren oder darauf klicken. Das Ändern der Schaltflächendarstellung, wenn sich diese in einem anderen Zustand befindet, wird weiter unten in diesem Thema erläutert.

In diesem Beispiel besteht die visuelle Struktur aus den folgenden Teilen:

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <!--Create the SolidColorBrush for the Background 
        as an object elemment and give it a name so 
        it can be referred to elsewhere in the
        control template.-->
    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <!--Create a border that has a different color
        by adding smaller grid. The background of 
        this grid is specificied by the button's 
        Background property.-->
    <Grid Margin="4" Background="{TemplateBinding Background}">

      <!--Use a ContentPresenter to display the Content of
          the Button.-->
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>

  </Border>
</ControlTemplate>

Beim Erstellen einer neuen ControlTemplate können Sie weiterhin die öffentlichen Eigenschaften verwenden, um die Darstellung des Steuerelements zu ändern. Die TemplateBinding-Markuperweiterung bindet eine Eigenschaft eines Elements in der ControlTemplate an eine vom Steuerelement definierte öffentliche Eigenschaft. Bei Verwendung von TemplateBinding können Eigenschaften des Steuerelements als Parameter der Vorlage fungieren. Wenn eine Eigenschaft für ein Steuerelement festgelegt wird, wird dieser Wert somit an das Element übergeben, für das TemplateBinding angegeben ist.

Im folgenden Beispiel wird der Teil des vorherigen Beispiels wiederholt, der die TemplateBinding-Markuperweiterung verwendet, um Eigenschaften von Elementen in der ControlTemplate an von der Schaltfläche definierte öffentliche Eigenschaften zu binden.

<Grid Margin="4" Background="{TemplateBinding Background}">

  <!--Use a ContentPresenter to display the Content of
      the Button.-->
  <ContentPresenter
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Margin="4,5,4,4" />
</Grid>

In diesem Beispiel ist die Panel.Background-Eigenschaftenvorlage für das Grid an Control.Background gebunden. Da Panel.Background vorlagengebunden ist, können Sie mehrere Schaltflächen erstellen, die dieselbe ControlTemplate verwenden, und den Control.Background für jede Schaltfläche auf einen anderen Wert festlegen. Wenn Control.Background in der ControlTemplate nicht an die Eigenschaft eines Elements vorlagengebunden ist, hat das Festlegen des Control.Background einer Schaltfläche keine Auswirkungen auf die Darstellung der Schaltfläche.

Beachten Sie, dass die Namen der zwei Eigenschaften nicht identisch sein müssen. Im vorherigen Beispiel ist die Control.HorizontalContentAlignment-Eigenschaft der Button an die FrameworkElement.HorizontalAlignment-Eigenschaft des ContentPresenter vorlagengebunden. Dadurch kann der Inhalt der Schaltfläche horizontal positioniert werden. ContentPresenter verfügt nicht über eine Eigenschaft mit dem Namen HorizontalContentAlignment, aber Control.HorizontalContentAlignment kann an FrameworkElement.HorizontalAlignment gebunden werden. Wenn Sie eine Eigenschaft an eine Vorlage binden, stellen Sie sicher, dass die Ziel und Quelleigenschaften denselben Typ aufweisen.

Die Control-Klasse definiert eine Reihe von Eigenschaften, die von der Steuerelementvorlage verwendet werden müssen und Auswirkungen auf das Steuerelement haben, wenn sie festgelegt werden. Die Verwendung der Eigenschaft durch die ControlTemplate ist von der Eigenschaft abhängig. Die ControlTemplate muss die Eigenschaft auf eine der folgenden Weisen verwenden:

In der folgenden Tabelle sind die visuellen Eigenschaften aufgelistet, die ein Steuerelement von der Control-Klasse geerbt hat. Sie gibt auch an, ob die standardmäßige Steuerelementvorlage eines Steuerelements den geerbten Eigenschaftswert verwendet oder ob es vorlagengebunden sein muss.

Property

Verwendungsart

Background

Vorlagenbindung

BorderThickness

Vorlagenbindung

BorderBrush

Vorlagenbindung

FontFamily

Eigenschaftenvererbung oder Vorlagenbindung

FontSize

Eigenschaftenvererbung oder Vorlagenbindung

FontStretch

Eigenschaftenvererbung oder Vorlagenbindung

FontWeight

Eigenschaftenvererbung oder Vorlagenbindung

Foreground

Eigenschaftenvererbung oder Vorlagenbindung

HorizontalContentAlignment

Vorlagenbindung

Padding

Vorlagenbindung

VerticalContentAlignment

Vorlagenbindung

In der Tabelle werden nur die von der Control-Klasse geerbten visuellen Eigenschaften aufgelistet. Abgesehen von den in der Tabelle aufgelisteten Eigenschaften kann ein Steuerelement möglicherweise auch die Eigenschaften DataContext, Language und TextDecorations vom übergeordneten Frameworkelement erben.

Wenn sich zudem der ContentPresenter in der ControlTemplate eines ContentControl befindet, wird der ContentPresenter automatisch an die ContentTemplate-Eigenschaft und die Content-Eigenschaft gebunden. Entsprechend wird ein ItemsPresenter, der sich in der ControlTemplate eines ItemsControl befindet, automatisch an die Items-Eigenschaft und die ItemsPresenter-Eigenschaft gebunden.

Im folgenden Beispiel werden zwei Schaltflächen erstellt, für die die im vorherigen Beispiel definierte ControlTemplate verwendet wird. Im folgenden Beispiel werden die Eigenschaften Background, Foreground und FontSize für die einzelnen Schaltflächen festgelegt. Das Festlegen der Background-Eigenschaft wirkt sich aus, da diese in der ControlTemplate vorlagengebunden ist. Obwohl die Foreground-Eigenschaft und die FontSize-Eigenschaft nicht vorlagengebunden sind, wirkt sich das Festlegen aus, da deren Werte geerbt werden.

<StackPanel>
  <Button Style="{StaticResource newTemplate}" 
          Background="Navy" Foreground="White" FontSize="14"
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}" 
          Background="Purple" Foreground="White" FontSize="14"
          Content="Button2" HorizontalContentAlignment="Left"/>
</StackPanel>

Die Ausgabe im vorhergehenden Beispiel ähnelt der folgenden Abbildung.

Zwei Schaltflächen, eine blaue und eine violette.

Zwei Schaltflächen mit unterschiedlichen Hintergrundfarben

Der Unterschied zwischen einer Schaltfläche in der Standarddarstellung und der Schaltfläche im vorherigen Beispiel besteht darin, dass die Standardschaltfläche je nach Zustand leicht geändert wird. Zum Beispiel wird die Darstellung der Standardschaltfläche geändert, wenn auf die Schaltfläche geklickt wird oder sich der Mauszeiger über der Schaltfläche befindet. Zwar wird mit der ControlTemplate nicht die Funktionalität eines Steuerelements, aber das visuelle Verhalten des Steuerelements geändert. Das visuelle Verhalten beschreibt die Darstellung eines Steuerelements in bestimmten Zuständen. Zur Verdeutlichung des Unterschieds zwischen Funktionalität und visuellem Verhalten eines Steuerelements betrachten Sie das Schaltflächenbeispiel. Die Funktionalität der Schaltfläche besteht im Auslösen des Click-Ereignisses, wenn auf sie geklickt wird. Das visuelle Verhalten der Schaltfläche hingegen besteht in der Änderung der Darstellung, wenn auf sie gezeigt oder geklickt wird.

Sie verwenden VisualState-Objekte, um die Darstellung eines Steuerelements anzugeben, wenn sich dieses in einem bestimmten Zustand befindet. Ein VisualState enthält ein Storyboard, das die Darstellung der Elemente in der ControlTemplate ändert. Sie müssen zu diesem Zweck keinen Code schreiben, da aufgrund der Logik des Steuerelements der Zustand über den VisualStateManager geändert wird. Wenn das Steuerelement in den von der VisualState.Name-Eigenschaft angegebenen Zustand eintritt, wird das Storyboard gestartet. Wenn das Steuerelement den Zustand verlässt, wird das Storyboard beendet.

Im folgenden Beispiel wird der VisualState veranschaulicht, der die Darstellung einer Button ändert, wenn sich die Mauszeiger darüber befindet. Das Storyboard ändert die Rahmenfarbe der Schaltfläche durch Änderung der Farbe des BorderBrush. Erinnern Sie sich an das Beispiel mit der ControlTemplate am Anfang dieses Themas. BorderBrush ist der Name des SolidColorBrush, der dem Background der Border zugewiesen wurde.

<!--Change the border of the button to red when the
    mouse is over the button.-->
<VisualState x:Name="MouseOver">
  <Storyboard>
    <ColorAnimation Storyboard.TargetName="BorderBrush"     
                    Storyboard.TargetProperty="Color"
                    To="Red" />

  </Storyboard>
</VisualState>

Das Steuerelement ist für die Definition der Zustände als Teil des Steuerelementvertrags verantwortlich. Dies wird weiter unten in diesem Thema detailliert unter Anpassen anderer Steuerelemente durch Kenntnisse des Steuerelementvertrags besprochen. In der folgenden Tabelle werden die für Button angegebenen Zustände aufgelistet.

VisualState-Name

VisualStateGroup-Name

Beschreibung

Normal

CommonStates

Der Standardzustand.

MouseOver

CommonStates

Der Mauszeiger ist über dem Steuerelement positioniert.

Pressed

CommonStates

Das Steuerelement wird gedrückt.

Disabled

CommonStates

Das Steuerelement ist deaktiviert.

Focused

FocusStates

Das Steuerelement besitzt den Fokus.

Unfocused

FocusStates

Der Fokus liegt nicht auf dem Steuerelement.

Die Button definiert zwei Zustandsgruppen: die Gruppe CommonStates enthält die Zustände Normal, MouseOver, Pressed und Disabled. Die Gruppe FocusStates enthält die Zustände Focused und Unfocused. Zustände in derselben Zustandsgruppe schließen sich gegenseitig aus. Das Steuerelement befindet sich immer in genau einem Zustand aus jeder Gruppe. Zum Beispiel kann ein Button den Fokus selbst dann besitzen, wenn sich der Mauszeiger nicht darüber befindet. Daher kann sich ein Button im Zustand Focused im Zustand MouseOver, Pressed oder Normal befinden.

Sie fügen VisualState-Objekte VisualStateGroup-Objekten hinzu. Sie fügen der angefügten VisualStateManager.VisualStateGroups-Eigenschaft VisualStateGroup-Objekte hinzu. Im folgenden Beispiel werden die VisualState-Objekte für die Zustände Normal, MouseOver und Pressed definiert, die jeweils der CommonStates-Gruppe angehören. Der Name von jedem VisualState stimmt mit dem Namen in der vorangehenden Tabelle überein. Der Zustand Disabled sowie die Zustände in der FocusStates-Gruppe werden ausgelassen, um das Beispiel kurz zu halten, im vollständigen Beispiel am Ende dieses Themas sind diese jedoch enthalten.

System_CAPS_noteHinweis

Die angefügte VisualStateManager.VisualStateGroups-Eigenschaft muss für das Stamm-FrameworkElement der ControlTemplate festgelegt werden.

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <VisualStateManager.VisualStateGroups>

      <!--Define the states and transitions for the common states.
          The states in the VisualStateGroup are mutually exclusive to
          each other.-->
      <VisualStateGroup Name="CommonStates">

        <!--The Normal state is the state the button is in
            when it is not in another state from this VisualStateGroup.-->
        <VisualState Name="Normal" />

        <!--Change the SolidColorBrush, BorderBrush, to red when the
            mouse is over the button.-->
        <VisualState Name="MouseOver">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color" 
                            To="Red" />
          </Storyboard>
        </VisualState>

        <!--Change the SolidColorBrush, BorderBrush, to Transparent when the
            button is pressed.-->
        <VisualState Name="Pressed">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color"
                            To="Transparent"/>
          </Storyboard>
        </VisualState>

        <!--The Disabled state is omitted for brevity.-->
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <Grid Background="{TemplateBinding Background}" Margin="4">
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>
  </Border>
</ControlTemplate>

Die Ausgabe im vorhergehenden Beispiel ähnelt den folgenden Abbildungen.

Schaltfläche mit einer benutzerdefinierten Steuerelementvorlage.

Eine Schaltfläche, die eine benutzerdefinierte Steuerelementvorlage im normalen Zustand verwendet

Schaltfläche mit einem roten Rahmen.

Eine Schaltfläche, die eine benutzerdefinierte Steuerelementvorlage im MouseOver-Zustand verwendet

Der Rahmen ist bei Klicken auf Schaltfläche transparent.

Eine Schaltfläche, die eine benutzerdefinierte Steuerelementvorlage im gedrückten Zustand verwendet

Die visuellen Zustände für Steuerelemente in WPF finden Sie unter Steuerelementformate und -vorlagen.

Im vorausgehenden Beispiel ändert sich die Darstellung der Schaltfläche auch, wenn der Benutzer darauf klickt, jedoch sieht der Benutzer den Effekt nur, wenn die Schaltfläche eine volle Sekunde lang gedrückt wird. Standardmäßig benötigt die Animation eine Sekunde, bevor sie sichtbar wird. Da Benutzer wahrscheinlich in einer wesentlich kürzeren Zeit auf eine Schaltfläche klicken und diese wieder loslassen, wird das visuelle Feedback nicht sichtbar, wenn Sie die ControlTemplate im Standardzustand belassen.

Sie können den Zeitraum angeben, den eine Animation für den Übergang eines Steuerelements von einem Zustand in einen anderen benötigt, indem Sie der ControlTemplateVisualTransition-Objekte hinzufügen. Beim Erstellen einer VisualTransition können Sie eines oder mehrere der folgenden Elemente angeben:

  • Die Zeit für einen Wechsel zwischen Zuständen

  • Zusätzliche Änderungen in der Darstellung des Steuerelements zur Zeit des Übergangs

  • Die Zustände, auf die der VisualTransition angewendet wird

Sie können die Dauer eines Übergangs angeben, indem Sie die GeneratedDuration-Eigenschaft festlegen. Das vorherige Beispiel hat einen VisualState, der angibt, dass der Rahmen der Schaltfläche beim Klicken auf die Schaltfläche transparent wird. Die Animation dauert jedoch zu lang, um bemerkt zu werden, wenn schnell auf die Schaltfläche geklickt und wieder losgelassen wird. Mit einer VisualTransition können Sie die Zeitdauer angeben, die das Steuerelement für den Übergang in den gedrückten Zustand benötigt. Im folgenden Beispiel wird angegeben, dass das Steuerelement für den Übergang in den gedrückten Zustand eine Hundertstelsekunde benötigt.

<!--Take one hundredth of a second to transition to the
    Pressed state.-->
<VisualTransition To="Pressed" 
                  GeneratedDuration="0:0:0.01" />

Der VisualTransition enthält ein Storyboard, das gestartet wird, wenn das Steuerelement den Zustand wechselt. Zum Beispiel können Sie angeben, dass eine bestimmte Animation ausgeführt wird, wenn das Steuerelement aus dem Zustand MouseOver in den Zustand Normal übergeht. Im folgenden Beispiel wird ein VisualTransition erstellt, der angibt, dass der Rahmen der Schaltfläche in 1,5 Sekunden von blau über gelb nach schwarz wechselt, wenn der Benutzer den Mauszeiger von der Schaltfläche weg bewegt.

<!--Take one and a half seconds to transition from the
    MouseOver state to the Normal state. 
    Have the SolidColorBrush, BorderBrush, fade to blue, 
    then to yellow, and then to black in that time.-->
<VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
  <Storyboard>
    <ColorAnimationUsingKeyFrames
      Storyboard.TargetProperty="Color"
      Storyboard.TargetName="BorderBrush"
      FillBehavior="HoldEnd" >

      <ColorAnimationUsingKeyFrames.KeyFrames>

        <LinearColorKeyFrame Value="Blue" 
          KeyTime="0:0:0.5" />
        <LinearColorKeyFrame Value="Yellow" 
          KeyTime="0:0:1" />
        <LinearColorKeyFrame Value="Black" 
          KeyTime="0:0:1.5" />

      </ColorAnimationUsingKeyFrames.KeyFrames>
    </ColorAnimationUsingKeyFrames>
  </Storyboard>
</VisualTransition>

Die Anwendung eines VisualTransition kann auf bestimmte Zustände beschränkt werden oder auch bei jedem Wechsel des Steuerelements zwischen Zuständen ausgeführt werden. Im vorherigen Beispiel wird der VisualTransition angewendet, wenn das Steuerelement aus dem Zustand MouseOver in den Zustand Normal wechselt. Im Beispiel davor wird der VisualTransition angewendet, wenn das Steuerelement in den Zustand Pressed wechselt. Die Anwendung eines VisualTransition schränken Sie ein, indem Sie die To-Eigenschaft und die From-Eigenschaft festlegen. In der folgenden Tabelle werden die Beschränkungsebenen von der restriktivsten bis zur am wenigsten restriktiven beschrieben.

Beschränkungstyp

From-Wert

To-Wert

Aus einem angegebenen Zustand in einen anderen angegebenen Zustand

Der Name eines VisualState.

Der Name eines VisualState.

Aus einem beliebigen Zustand in einen angegebenen Zustand

Nicht festgelegt

Der Name eines VisualState.

Aus einem angegebenen Zustand in einen beliebigen Zustand

Der Name eines VisualState.

Nicht festgelegt

Aus einem beliebigen Zustand in einen beliebigen anderen Zustand

Nicht festgelegt

Nicht festgelegt

Mehrere VisualTransition-Objekte in einer VisualStateGroup können auf denselben Zustand verweisen, doch werden diese in der Reihenfolge verwendet, die in der vorherigen Tabelle angegeben ist. Im folgenden Beispiel sind zwei VisualTransition-Objekte vorhanden. Wenn das Steuerelement aus dem Zustand Pressed in den Zustand MouseOver übergeht, wird die VisualTransition verwendet, für die From und To festgelegt sind. Wenn das Steuerelement aus einem anderen Zustand als Pressed in den Zustand MouseOver übergeht, wird der andere Zustand verwendet.

<!--Take one half second to trasition to the MouseOver state.-->
<VisualTransition To="MouseOver" 
                  GeneratedDuration="0:0:0.5" />

<!--Take one hundredth of a second to transition from the
    Pressed state to the MouseOver state.-->
<VisualTransition From="Pressed" To="MouseOver" 
                  GeneratedDuration="0:0:0.01" />

Die VisualStateGroup besitzt eine Transitions-Eigenschaft, die die VisualTransition-Objekte enthält, die auf die VisualState-Objekte in der VisualStateGroup angewendet werden. Als Autor der ControlTemplate können Sie eine beliebige VisualTransition einfügen. Wenn die To-Eigenschaft und die From-Eigenschaft jedoch auf Zustandsnamen festgelegt sind, die in der VisualStateGroup nicht enthalten sind, wird die VisualTransition ignoriert.

Im folgenden Beispiel wird die VisualStateGroup für die CommonStates veranschaulicht. Im Beispiel wird eine VisualTransition für jeden der folgenden Übergänge der Schaltfläche definiert.

  • In den Zustand Pressed.

  • In den Zustand MouseOver.

  • Aus dem Zustand Pressed in den Zustand MouseOver.

  • Aus dem Zustand MouseOver in den Zustand Normal.

<VisualStateGroup Name="CommonStates">

  <!--Define the VisualTransitions that
      can be used when the control transitions 
      between VisualStates that are defined in the
      VisualStatGroup.-->
  <VisualStateGroup.Transitions>

    <!--Take one hundredth of a second to 
        transition to the Pressed state.-->
    <VisualTransition To="Pressed" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one half second to trasition 
        to the MouseOver state.-->
    <VisualTransition To="MouseOver" 
                      GeneratedDuration="0:0:0.5" />

    <!--Take one hundredth of a second to transition from the
        Pressed state to the MouseOver state.-->
    <VisualTransition From="Pressed" To="MouseOver" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one and a half seconds to transition from the
        MouseOver state to the Normal state. 
        Have the SolidColorBrush, BorderBrush, fade to blue, 
        then to yellow, and then to black in that time.-->
    <VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
      <Storyboard>
        <ColorAnimationUsingKeyFrames
          Storyboard.TargetProperty="Color"
          Storyboard.TargetName="BorderBrush"
          FillBehavior="HoldEnd" >

          <ColorAnimationUsingKeyFrames.KeyFrames>
            <LinearColorKeyFrame Value="Blue" 
              KeyTime="0:0:0.5" />
            <LinearColorKeyFrame Value="Yellow" 
              KeyTime="0:0:1" />
            <LinearColorKeyFrame Value="Black" 
              KeyTime="0:0:1.5" />

          </ColorAnimationUsingKeyFrames.KeyFrames>
        </ColorAnimationUsingKeyFrames>
      </Storyboard>
    </VisualTransition>
  </VisualStateGroup.Transitions>

  <!--The remainder of the VisualStateGroup is the
      same as the previous example.-->

  <VisualState Name="Normal" />

  <VisualState Name="MouseOver">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Red" />

    </Storyboard>
  </VisualState>

  <VisualState Name="Pressed">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Transparent"/>
    </Storyboard>
  </VisualState>

  <!--The Disabled state is omitted for brevity.-->

</VisualStateGroup>

Für ein Steuerelement, dessen visuelle Struktur (über FrameworkElement-Objekte) und visuelles Verhalten (über VisualState-Objekte) in einer ControlTemplate angegeben werden, wird das Parts-Steuerelementmodell verwendet. Viele der Steuerelemente, die in WPF 4 enthalten sind, verwenden dieses Modell. Die Teile, auf die ControlTemplate-Autoren achten müssen, sind im Steuerelementvertrag aufgeführt. Wenn Sie mit den Teilen eines Steuerelementvertrags vertraut sind, können Sie die Darstellung jedes Steuerelements anpassen, für das das Parts-Steuerelementmodell verwendet wird.

Ein Steuerelementvertrag besteht aus drei Elementen:

  • Den von der Logik des Steuerelements verwendeten visuellen Elementen

  • Den Zuständen des Steuerelements und den Gruppen, zu denen die einzelnen Zustände gehören

  • Die öffentlichen Eigenschaften, die sich auf das Steuerelement visuell auswirken

In manchen Fällen interagiert die Logik eines Steuerelements mit einem FrameworkElement in der ControlTemplate. Zum Beispiel kann das Steuerelement ein Ereignis für eines der zugehörigen Elemente behandeln. Wenn ein Steuerelement in der ControlTemplate ein bestimmtes FrameworkElement erwartet, muss es diese Informationen an den ControlTemplate-Autor leiten. Das Steuerelement übermittelt den erwarteten Elementtyp und den geforderten Elementnamen über das TemplatePartAttribute. Im Steuerelementvertrag sind für den Button keine FrameworkElement-Teile vorhanden, jedoch für andere Steuerelemente, beispielsweise die ComboBox.

Im folgenden Beispiel werden die für die ComboBox-Klasse angegebenen TemplatePartAttribute-Objekte veranschaulicht. Die Logik von ComboBox erwartet in der ControlTemplate das TextBox mit dem Namen PART_EditableTextBox und den Popup mit dem Namen PART_Popup.

[TemplatePartAttribute(Name = "PART_EditableTextBox", Type = typeof(TextBox))]
[TemplatePartAttribute(Name = "PART_Popup", Type = typeof(Popup))]
public class ComboBox : ItemsControl
{
}

Im folgenden Beispiel wird eine vereinfachte ControlTemplate für die ComboBox veranschaulicht, die die von den TemplatePartAttribute-Objekten für die ComboBox-Klasse angegebenen Elemente enthält.

<ControlTemplate TargetType="ComboBox">
  <Grid>
    <ToggleButton x:Name="DropDownToggle"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  
      Margin="-1" HorizontalContentAlignment="Right"
      IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
                  RelativeSource={RelativeSource TemplatedParent}}">
      <Path x:Name="BtnArrow" Height="4" Width="8" 
        Stretch="Uniform" Margin="0,0,6,0"  Fill="Black"
        Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
    </ToggleButton>
    <ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2"
      Content="{TemplateBinding SelectionBoxItem}"
      ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
      ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}">
    </ContentPresenter>
    <TextBox x:Name="PART_EditableTextBox"
      Style="{x:Null}"
      Focusable="False"
      Background="{TemplateBinding Background}"
      HorizontalAlignment="Left" 
      VerticalAlignment="Center" 
      Margin="3,3,23,3"
      Visibility="Hidden"
      IsReadOnly="{TemplateBinding IsReadOnly}"/>

    <Popup x:Name="PART_Popup"
      IsOpen="{TemplateBinding IsDropDownOpen}">
      <Border x:Name="PopupBorder" 
        HorizontalAlignment="Stretch" Height="Auto" 
        MinWidth="{TemplateBinding ActualWidth}"
        MaxHeight="{TemplateBinding MaxDropDownHeight}"
        BorderThickness="{TemplateBinding BorderThickness}" 
        BorderBrush="Black" Background="White" CornerRadius="3">
        <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
          <ItemsPresenter/>
        </ScrollViewer>
      </Border>
    </Popup>

  </Grid>
</ControlTemplate>

Die Zustände eines Steuerelements sind ebenfalls Teil des Steuerelementvertrags. Im Beispiel zum Erstellen einer ControlTemplate für einen Button wird gezeigt, wie die Darstellung eines Button in Abhängigkeit von dessen Zuständen angegeben wird. Sie erstellen einen VisualState für jeden angegebenen Zustand und haben alle VisualState-Objekte gesetzt, für die ein GroupName in einem VisualStateGroup freigegeben ist, wie unter Ändern der Darstellung eines Steuerelements in Abhängigkeit von dessen Zustand weiter oben in diesem Thema beschrieben. Steuerelemente von Drittanbietern sollten Zustände festlegen, indem sie TemplateVisualStateAttributeverwenden, die Designertools, z. B. Expression Blend die Zustände des Steuerelements zum Erstellen von Steuerelementvorlagen verfügbar zu machen.

Den Steuerelementvertrag für Steuerelemente in WPF finden Sie unter Steuerelementformate und -vorlagen.

Die öffentlichen Eigenschaften, die sich auf das Steuerelement visuell auswirken, sind ebenfalls im Steuerelementvertrag enthalten. Diese Eigenschaften können Sie festlegen, um die Darstellung des Steuerelements zu ändern, ohne eine neue ControlTemplate erstellen zu müssen. Sie können auch die TemplateBinding-Markuperweiterung verwenden, um Eigenschaften von Elementen in der ControlTemplate an öffentliche Eigenschaften zu binden, die vom Button definiert werden.

Das folgende Beispiel zeigt den Steuerelementvertrag für die Schaltfläche.

[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
public class Button : ButtonBase
{
    public static readonly DependencyProperty BackgroundProperty;
    public static readonly DependencyProperty BorderBrushProperty;
    public static readonly DependencyProperty BorderThicknessProperty;
    public static readonly DependencyProperty ContentProperty;
    public static readonly DependencyProperty ContentTemplateProperty;
    public static readonly DependencyProperty FontFamilyProperty;
    public static readonly DependencyProperty FontSizeProperty;
    public static readonly DependencyProperty FontStretchProperty;
    public static readonly DependencyProperty FontStyleProperty;
    public static readonly DependencyProperty FontWeightProperty;
    public static readonly DependencyProperty ForegroundProperty;
    public static readonly DependencyProperty HorizontalContentAlignmentProperty;
    public static readonly DependencyProperty PaddingProperty;
    public static readonly DependencyProperty TextAlignmentProperty;
    public static readonly DependencyProperty TextDecorationsProperty;
    public static readonly DependencyProperty TextWrappingProperty;
    public static readonly DependencyProperty VerticalContentAlignmentProperty;

    public Brush Background { get; set; }
    public Brush BorderBrush { get; set; }
    public Thickness BorderThickness { get; set; }
    public object Content { get; set; }
    public DataTemplate ContentTemplate { get; set; }
    public FontFamily FontFamily { get; set; }
    public double FontSize { get; set; }
    public FontStretch FontStretch { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontWeight FontWeight { get; set; }
    public Brush Foreground { get; set; }
    public HorizontalAlignment HorizontalContentAlignment { get; set; }
    public Thickness Padding { get; set; }
    public TextAlignment TextAlignment { get; set; }
    public TextDecorationCollection TextDecorations { get; set; }
    public TextWrapping TextWrapping { get; set; }
    public VerticalAlignment VerticalContentAlignment { get; set; }
}

Beim Erstellen einer ControlTemplate ist es oft am einfachsten, mit einer vorhandenen ControlTemplate zu beginnen und an dieser Änderungen vorzunehmen. Zum Ändern einer vorhandenen ControlTemplate können Sie wie folgt vorgehen:

Im folgenden Beispiel wird die vollständige ButtonControlTemplate dargestellt, die in diesem Thema erläutert wird.

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="Button" x:Key="newTemplate">
      <!--Set the Background, Foreground, FontSize, Width, 
                  Height, Margin, and Template properties for
                  the Button.-->
      <Setter Property="Background" Value="Navy"/>
      <Setter Property="Foreground" Value="White"/>
      <Setter Property="FontSize" Value="14"/>
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Margin" Value="10"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border x:Name="RootElement">
              <VisualStateManager.VisualStateGroups>

                <!--Define the states and transitions for the common states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup Name="CommonStates">

                  <!--Define the VisualTransitions that can be used when the control
                      transitions between VisualStates that are defined in the
                      VisualStatGroup.-->
                  <VisualStateGroup.Transitions>

                    <!--Take one hundredth of a second to transition to the
                        Pressed state.-->
                    <VisualTransition To="Pressed" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one half second to trasition to the MouseOver state.-->
                    <VisualTransition To="MouseOver" 
                                      GeneratedDuration="0:0:0.5" />

                    <!--Take one hundredth of a second to transition from the
                        Pressed state to the MouseOver state.-->
                    <VisualTransition From="Pressed" To="MouseOver" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one and a half seconds to transition from the
                        MouseOver state to the Normal state. 
                        Have the SolidColorBrush, BorderBrush, fade to blue, 
                        then to yellow, and then to black in that time.-->
                    <VisualTransition From="MouseOver" To="Normal" 
                                          GeneratedDuration="0:0:1.5">
                      <Storyboard>
                        <ColorAnimationUsingKeyFrames
                          Storyboard.TargetProperty="Color"
                          Storyboard.TargetName="BorderBrush"
                          FillBehavior="HoldEnd" >

                          <ColorAnimationUsingKeyFrames.KeyFrames>

                            <LinearColorKeyFrame Value="Blue" 
                              KeyTime="0:0:0.5" />
                            <LinearColorKeyFrame Value="Yellow" 
                              KeyTime="0:0:1" />
                            <LinearColorKeyFrame Value="Black" 
                              KeyTime="0:0:1.5" />

                          </ColorAnimationUsingKeyFrames.KeyFrames>
                        </ColorAnimationUsingKeyFrames>
                      </Storyboard>
                    </VisualTransition>
                  </VisualStateGroup.Transitions>

                  <!--The Normal state is the state the button is in
                      when it is not in another state from this VisualStateGroup.
                      There is no special visual behavior for this state, but
                      the VisualState must be defined in order for the button
                      to return to its initial state.-->
                  <VisualState x:Name="Normal" />

                  <!--Change the border of the button to red when the
                      mouse is over the button.-->
                  <VisualState x:Name="MouseOver">
                    <Storyboard>
                      <ColorAnimation Storyboard.TargetName="BorderBrush"     
                                      Storyboard.TargetProperty="Color"
                                      To="Red" />

                    </Storyboard>
                  </VisualState>

                  <!--Change the border of the button to Transparent when the
                      button is pressed.-->
                  <VisualState x:Name="Pressed">
                    <Storyboard >
                      <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                      Storyboard.TargetProperty="Color" 
                                      To="Transparent" 
                                      />
                    </Storyboard>
                  </VisualState>

                  <!--Show the DisabledRect when the IsEnabled property on
                      the button is false.-->
                  <VisualState x:Name="Disabled">
                    <Storyboard>
                      <DoubleAnimation Storyboard.TargetName="DisabledRect" 
                                       Storyboard.TargetProperty="Opacity"
                                       To="1" Duration="0" />
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>

                <!--Define the states and transitions for the focus states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup x:Name="FocusStates">

                  <!--Define the VisualStates in this VistualStateGroup.-->
                  <VisualState x:Name="Focused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility" Duration
                        ="0">

                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                  <VisualState x:Name="Unfocused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility"
                        Duration="0">

                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>
              </VisualStateManager.VisualStateGroups>

              <!--Create the SolidColorBrush for the Background 
                  as an object elemment and give it a name so 
                  it can be referred to elsewhere in the control template.-->
              <Border.Background>
                <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
              </Border.Background>

              <!--Create a border that has a different color by adding smaller grid.
                  The background of this grid is specified by the button's Background
                  property.-->
              <Grid Background="{TemplateBinding Background}" Margin="4">

                <!--Create a Rectangle that indicates that the
                    Button has focus.-->
                <Rectangle Name="FocusVisual" 
                           Visibility="Collapsed" Margin="2" 
                           Stroke="{TemplateBinding Foreground}" 
                           StrokeThickness="1" 
                           StrokeDashArray="1.5 1.5"/>

                <!--Use a ContentPresenter to display the Content of
                    the Button.-->
                <ContentPresenter
                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                  Margin="4,5,4,4" />

                <!--Create a rectangle that causes the button to appear
                    grayed out when it is disabled.-->
                <Rectangle x:Name="DisabledRect" 
                         Fill="#A5FFFFFF"
                         Opacity="0" IsHitTestVisible="false" />
              </Grid>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </StackPanel.Resources>

  <Button Style="{StaticResource newTemplate}" 
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}"
          Background="Purple" 
          Content="Button2" />
</StackPanel>
Anzeigen: