Freigeben über


Übersicht über Storyboards

Aktualisiert: November 2007

In diesem Thema wird gezeigt, wie mit Storyboard-Objekten Animationen organisiert und angewendet werden. Es wird beschrieben, wie Storyboard-Objekte interaktiv bearbeitet werden. Außerdem wird die Syntax für die indirekte Verwendung von Eigenschaften beschrieben.

Vorbereitungsmaßnahmen

Für dieses Thema sollten Sie mit den verschiedenen Animationstypen und ihren grundlegenden Features vertraut sein. Eine Einführung in Animationsfeatures finden Sie unter Übersicht über Animationen. Sie sollten auch wissen, wie angefügte Eigenschaften verwendet werden. Weitere Informationen über angefügte Eigenschaften finden Sie unter Übersicht über angefügte Eigenschaften.

Was ist ein Storyboard?

Animationen sind nicht der einzige nützliche Zeitachsentyp. Es stehen andere Zeitachsenklassen zur Verfügung, um bei der Organisation von Zeitachsengruppen zu helfen und Zeitachsen auf Eigenschaften anzuwenden. Containerzeitachsen sind von der TimelineGroup-Klasse abgeleitet und enthalten ParallelTimeline und Storyboard.

Ein Storyboard ist ein Typ von Containerzeitachse, der Zielinformationen für die Zeitachsen zur Verfügung stellt, die sie enthält. Ein Storyboard kann jeden Typ von Timeline enthalten, auch andere Containerzeitachsen und -animationen. Mit Storyboard-Objekten können Sie Zeitachsen kombinieren, die eine Vielzahl von Objekten und Eigenschaften in einer einzelnen Zeitachsenstruktur beeinflussen können, wodurch komplexes Zeitverhalten einfach organisiert und gesteuert werden kann. Angenommen, eine Schaltfläche soll Folgendes ausführen.

  • Größer werden und die Farbe ändern, wenn der Benutzer die Schaltfläche auswählt.

  • Kleiner werden und dann wieder auf die ursprüngliche Größe wachsen, wenn auf die Schaltfläche geklickt wird.

  • Kleiner und zu 50 Prozent durchlässig werden, wenn die Schaltfläche deaktiviert dargestellt wird.

In diesem Fall stehen mehrere Sätze von Animationen zur Verfügung, die auf dasselbe Objekt angewendet werden und die Sie je nach Zustand der Schaltfläche zu unterschiedlichen Zeiten wiedergeben möchten. Mit Storyboard-Objekten können Sie Animationen organisieren und sie in Gruppen auf ein oder mehrere Objekte anwenden.

Wo können Sie ein Storyboard verwenden?

Mit einem Storyboard können Sie Abhängigkeitseigenschaften von animierbaren Klassen animieren (weitere Informationen darüber, wodurch eine Klasse animierbar wird, finden Sie unter Übersicht über Animationen). Da der Einsatz von Storyboards ein Feature auf Frameworkebene ist, muss das Objekt allerdings zum NameScope eines FrameworkElement oder eines FrameworkContentElement gehören.

Mit einem Storyboard können Sie zum Beispiel:

Sie können aber mit einem Storyboard keinen SolidColorBrush animieren, der seinen Namen nicht bei einem FrameworkElement oder einem FrameworkContentElement registriert hat oder der nicht verwendet wurde, um eine Eigenschaft von einem FrameworkElement oder einem FrameworkContentElement festzulegen.

Anwenden von Animationen mit einem Storyboard

Um mit einem Storyboard Animationen zu organisieren und anzuwenden, fügen Sie die Animationen als untergeordnete Zeitachsen von Storyboard hinzu. Die Storyboard-Klasse stellt die angefügten Eigenschaften Storyboard.TargetName und Storyboard.TargetProperty zur Verfügung. Diese Eigenschaften werden für eine Animation festgelegt, um deren Zielobjekt und Eigenschaft anzugeben.

Um Animationen auf ihre Ziele anzuwenden, starten Sie das Storyboard mit einer Triggeraktion oder einer Methode. In XAML verwenden Sie ein BeginStoryboard-Objekt mit einem EventTrigger, Trigger oder DataTrigger. In Code können Sie auch die Begin-Methode verwenden.

Die folgende Tabelle zeigt die unterschiedlichen Stellen, an denen die einzelnen Verfahren zum Starten von Storyboard unterstützt werden: Pro Instanz, Stil, Steuerelementvorlage und Datenvorlage. "Pro Instanz" bezieht sich auf das Verfahren, wonach eine Animation oder ein Storyboard auf die Objektinstanzen direkt angewendet wird, und nicht in einem Stil, einer Steuerelementvorlage oder einer Datenvorlage.

Storyboard wird gestartet mit…

Pro Instanz

Style

Steuerelementvorlage

Datenvorlage

Beispiel

BeginStoryboard und einem EventTrigger

Ja

Ja

Ja

Ja

Gewusst wie: Animieren einer Eigenschaft unter Verwendung eines Storyboards

BeginStoryboard und einem Eigenschaften-Trigger

Nein

Ja

Ja

Ja

Gewusst wie: Auslösen einer Animation bei Änderung eines Eigenschaftenwerts

BeginStoryboard und einem DataTrigger

Nein

Ja

Ja

Ja

Gewusst wie: Auslösen einer Animation bei Datenänderungen

Begin-Methode

Ja

Nein

Nein

Nein

Gewusst wie: Animieren einer Eigenschaft unter Verwendung eines Storyboards

Im folgenden Beispiel werden mit einem Storyboard die Width eines Rectangle-Elements und die Color eines SolidColorBrush-Elements, mit dem das Rectangle gezeichnet wurde, animiert.

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.Animation.StoryboardsExample" 
  WindowTitle="Storyboards Example">
  <StackPanel Margin="20">

    <Rectangle Name="MyRectangle"
      Width="100"
      Height="100">
      <Rectangle.Fill>
        <SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
      </Rectangle.Fill>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetName="MyRectangle"
                Storyboard.TargetProperty="Width"
                From="100" To="200" Duration="0:0:1" />

              <ColorAnimation 
                Storyboard.TargetName="MySolidColorBrush"
                Storyboard.TargetProperty="Color"
                From="Blue" To="Red" Duration="0:0:1" />  
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle> 
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Data;
using System.Windows.Shapes;
using System.Windows.Input;


namespace Microsoft.Samples.Animation
{
    public class StoryboardsExample : Page
    {      
        public StoryboardsExample()
        {
            this.WindowTitle = "Storyboards Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "MyRectangle";

            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());            

            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
            this.RegisterName("MySolidColorBrush", mySolidColorBrush);
            myRectangle.Fill = mySolidColorBrush;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 100;
            myDoubleAnimation.To = 200;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, 
                new PropertyPath(Rectangle.WidthProperty));

            ColorAnimation myColorAnimation = new ColorAnimation();
            myColorAnimation.From = Colors.Blue;
            myColorAnimation.To = Colors.Red;
            myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
            Storyboard.SetTargetProperty(myColorAnimation, 
                new PropertyPath(SolidColorBrush.ColorProperty)); 
            Storyboard myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Children.Add(myColorAnimation);

            myRectangle.MouseEnter += delegate(object sender, MouseEventArgs e)
            {
                myStoryboard.Begin(this);
            };

            myStackPanel.Children.Add(myRectangle);
            this.Content = myStackPanel;
        } 
    }
}

In den folgenden Abschnitten werden die angefügten Eigenschaften TargetName und TargetProperty ausführlicher beschrieben.

Verwenden von Frameworkelementen, Frameworkinhaltselementen und Freezable-Objekten

Im vorhergehenden Abschnitt wurde erwähnt, dass einer Animation, der Zielname und die zu animierende Eigenschaft bekannt sein müssen, damit sie ihr Ziel findet. Das Angeben der zu animierenden Eigenschaft ist leicht: Legen Sie für Storyboard.TargetProperty einfach den Namen der zu animierenden Eigenschaft fest. Sie geben den Namen des Objekts, dessen Eigenschaft animiert werden soll, an, indem Sie die Storyboard.TargetName-Eigenschaft für die Animation festlegen.

Damit die TargetName-Eigenschaft eingesetzt werden kann, muss das Zielobjekt einen Namen besitzen. Einem FrameworkElement oder einem FrameworkContentElement in XAMLeinen Namen zuzuweisen, unterscheidet sich davon, einem Freezable-Objekt einen Namen zuzuweisen.

Frameworkelemente sind die Klassen, die von der FrameworkElement-Klasse erben. Zu den Frameworkelementen zählen Window, DockPanel, Button und Rectangle. Im Prinzip sind alle Fenster, Bereiche und Steuerelemente Elemente. Frameworkinhaltselemente sind die Klassen, die von der FrameworkContentElement-Klasse erben. Zu den Frameworkinhaltselementen zählen FlowDocument und Paragraph. Wenn Sie nicht sicher sind, ob es sich bei einem Typ um ein Frameworkelement oder ein Frameworkinhaltselelement handelt, überprüfen Sie, ob es eine Name-Eigenschaft besitzt. Trifft dies zu, handelt es sich wahrscheinlich um ein Frameworkelement oder ein Frameworkinhaltselement. Um sicherzugehen, überprüfen Sie den Abschnitt Vererbungshierarchie der Typseite.

Um die Verwendung eines Frameworkelements oder eines Frameworkinhaltselements in XAML zu aktivieren, legen Sie dessen Name-Eigenschaft fest. Im Code müssen Sie außerdem mit der RegisterName-Methode den Elementnamen für das Element registrieren, für das Sie einen NameScope erstellt haben.

Im folgenden Beispiel, das aus dem vorherigen Beispiel stammt, wird einem Rectangle, einem Typ von FrameworkElement, der Name MyRectangle zugewiesen.

<Rectangle Name="MyRectangle"
  Width="100"
  Height="100">
Rectangle myRectangle = new Rectangle();
myRectangle.Name = "MyRectangle";

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());            

this.RegisterName(myRectangle.Name, myRectangle);

Wenn es einen Namen besitzt, können Sie eine Eigenschaft dieses Elements animieren.

<DoubleAnimation 
  Storyboard.TargetName="MyRectangle"
  Storyboard.TargetProperty="Width"
  From="100" To="200" Duration="0:0:1" />
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, 
    new PropertyPath(Rectangle.WidthProperty));

Freezable-Typen sind die Klassen, die von der Freezable-Klasse erben. Zu Freezable zählen SolidColorBrush, RotateTransform und GradientStop.

Damit ein Freezable-Objekt für eine Animation in XAML verwendet werden kann, weisen Sie ihm mit dem x:Name-Attribut einen Namen zu. Im Code registrieren Sie mit der RegisterName-Methode den Namen für das Element, für das Sie einen NameScope erstellt haben.

Im folgenden Beispiel wird einem Freezable-Objekt ein Name zugewiesen.

<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
this.RegisterName("MySolidColorBrush", mySolidColorBrush);

Das Objekt kann dann für eine Animation verwendet werden.

<ColorAnimation 
  Storyboard.TargetName="MySolidColorBrush"
  Storyboard.TargetProperty="Color"
  From="Blue" To="Red" Duration="0:0:1" />  
Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
Storyboard.SetTargetProperty(myColorAnimation, 
    new PropertyPath(SolidColorBrush.ColorProperty)); 

Storyboard-Objekte lösen die TargetName-Eigenschaft mithilfe von Namensbereichen auf. Weitere Informationen über WPF-Namensbereiche finden Sie unter WPF-Namescopes. Wenn die TargetName-Eigenschaft weggelassen wird, verwendet die Animation das Element, für das sie definiert ist. Im Fall von Stilen ist dies das formatierte Element.

Manchmal kann einem Freezable-Objekt ein Name nicht zugewiesen werden. Wenn z. B. ein Freezable-Objekt als Ressource deklariert ist oder verwendet wird, um einen Eigenschaftenwert in einem Stil festzulegen, kann ihm kein Name zugewiesen werden. Ohne Namen kann es nicht direkt verwendet werden, wohl aber indirekt. In den folgenden Abschnitten wird beschrieben, wie die indirekte Verwendung eingesetzt wird.

Indirekte Verwendung

Manchmal kann ein Freezable-Objekt nicht direkt für eine Animation verwendet werden, z. B. wenn das Freezable-Objekt als Ressource deklariert ist oder verwendet wird, um einen Eigenschaftenwert in einem Stil festzulegen. In diesen Fällen kann das Freezable-Objekt dennoch animiert werden, obwohl es sich nicht direkt verwenden lässt. Anstatt für die TargetName-Eigenschaft den Namen des Freezable-Objekts festzulegen, erhält sie den Namen des Elements, zu dem das Freezable-Objekt "gehört". Zum Beispiel gehört ein SolidColorBrush, mit dem die Fill eines Rechteckelements festgelegt wird, zu diesem Rechteck. Um den Pinsel zu animieren, legen Sie die TargetProperty der Animation mit einer Kette von Eigenschaften fest, die bei der Eigenschaft des Frameworkelements bzw. Frameworkinhaltselements beginnt, die mit dem Freezable-Objekt festgelegt wurde, und mit der zu animierenden Freezable-Eigenschaft endet.

<ColorAnimation 
  Storyboard.TargetName="Rectangle01"
  Storyboard.TargetProperty="Fill.Color"
  From="Blue" To="AliceBlue" Duration="0:0:1" />
DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Beachten Sie, dass ein Klon erstellt und dieser Klon animiert wird, wenn das Freezable-Objekt fixiert ist. Wenn dieser Fall eintritt, gibt die HasAnimatedProperties-Eigenschaft des ursprünglichen Objekts weiterhin false zurück, da das ursprüngliche Objekt eigentlich nicht animiert wird. Weitere Informationen über das Klonen finden Sie unter Übersicht über Freezable-Objekte.

Beachten Sie beim Einsatz der indirekten Verwendung von Eigenschaften auch, dass es möglich ist, Objekte zu verwenden, die nicht vorhanden sind. Angenommen, der Background einer bestimmten Schaltfläche wurde mit einem SolidColorBrush festgelegt, und Sie versuchen, dessen Farbe zu animieren, wenn der Hintergrund der Schaltfläche tatsächlich aber mit einem LinearGradientBrush festgelegt wurde. In diesen Fällen wird keine Ausnahme ausgelöst. Die Animation hat keinen sichtbaren Effekt, da LinearGradientBrush nicht auf Änderungen an der Color-Eigenschaft reagiert.

In den folgenden Abschnitten wird die Syntax für die indirekte Verwendung von Eigenschaften ausführlicher erklärt.

Indirekte Verwendung einer Eigenschaft eines Freezable-Objekts in XAML

Um eine Eigenschaft eines Freezable-Objekts in XAML zu verwenden, verwenden Sie die folgende Syntax.

ElementPropertyName.FreezablePropertyName

Speicherort

  • ElementPropertyName ist die Eigenschaft von FrameworkElement, die mit dem Freezable-Objekt festgelegt wird, und

  • FreezablePropertyName ist die zu animierende Eigenschaft des Freezable-Objekts.

Der folgende Code zeigt, wie die Color für einen SolidColorBrush animiert wird, mit dem die

Fill eines Rectangle-Elements festgelegt wird.

<Rectangle
  Name="Rectangle01"
  Height="100"
  Width="100"
  Fill="{StaticResource MySolidColorBrushResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation 
            Storyboard.TargetName="Rectangle01"
            Storyboard.TargetProperty="Fill.Color"
            From="Blue" To="AliceBlue" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

Manchmal müssen Sie ein Freezable-Objekt verwenden, das in einer Auflistung oder einem Array enthalten ist.

Um ein in einer Auflistung enthaltenes Freezable-Objekt zu verwenden, verwenden Sie die folgende Pfadsyntax.

ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Wobei CollectionIndex der Index des Objekts im Array oder in der Auflistung ist.

Angenommen, bei einem Rechteck wird eine TransformGroup-Ressource auf die RenderTransform-Eigenschaft angewendet, und Sie möchten eine der Transformationen animieren, die sie enthält.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>

Im folgenden Code wird veranschaulicht, wie die Angle-Eigenschaft der RotateTransform aus dem vorhergehenden Beispiel animiert wird.

<Rectangle
  Name="Rectangle02"
  Height="100"
  Width="100"
  Fill="Blue"
  RenderTransform="{StaticResource MyTransformGroupResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation 
            Storyboard.TargetName="Rectangle02"
            Storyboard.TargetProperty="RenderTransform.Children[1].Angle"
            From="0" To="360" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>  

Indirekte Verwendung einer Eigenschaft eines Freezable-Objekts in Code

In Code erstellen Sie ein PropertyPath-Objekt. Wenn Sie den PropertyPath erstellen, geben Sie einen Path und PathParameters an.

Um PathParameters zu erstellen, erstellen Sie ein Array vom Typ DependencyProperty, das eine Liste mit Bezeichnerfeldern der Abhängigkeitseigenschaft enthält. Das erste Bezeichnerfeld ist für die Eigenschaft von FrameworkElement oder FrameworkContentElement, die mit dem Freezable-Objekt festgelegt wird. Das nächste Bezeichnerfeld stellt die Eigenschaft des zu verwendenden FreezableElements dar. Sie können sich dies als eine Kette von Eigenschaften vorstellen, die das Freezable-Objekt mit dem FrameworkElement-Objekt verbindet.

Im folgenden Beispiel wird eine Kette von Abhängigkeitseigenschaften gezeigt, die die Color für einen SolidColorBrush verwenden, mit dem die Fill eines Rectangle-Elements festgelegt wird.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};

Sie müssen auch einen Path angeben. Ein Path ist eine String, mit der dem Path mitgeteilt wird, wie die PathParameters interpretiert werden. Folgende Syntax wird verwendet.

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Speicherort

  • OwnerPropertyArrayIndex ist der Index des DependencyProperty-Arrays, das den Bezeichner der Eigenschaft des FrameworkElement-Objekts enthält, die mit dem Freezable-Objekt festgelegt wird, und

  • FreezablePropertyArrayIndex ist der Index des DependencyProperty-Arrays, das den Bezeichner der zu verwendenden Eigenschaft enthält.

Im folgenden Beispiel wird der Path für die im vorhergehenden Beispiel definierten PathParameters dargestellt.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";

Im folgenden Beispiel wird eine Kombinationen von Code aus den vorhergehenden Beispielen verwenden, um die Color für einen SolidColorBrush zu animieren, mit dem die Fill eines Rectangle-Elements festgelegt wurde.

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope()); 

Rectangle rectangle01 = new Rectangle();
rectangle01.Name = "Rectangle01";   
this.RegisterName(rectangle01.Name, rectangle01);
rectangle01.Width = 100;
rectangle01.Height = 100;
rectangle01.Fill = 
    (SolidColorBrush)this.Resources["MySolidColorBrushResource"];

ColorAnimation myColorAnimation = new ColorAnimation();
myColorAnimation.From = Colors.Blue;
myColorAnimation.To = Colors.AliceBlue;
myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myColorAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle01.Triggers.Add(myMouseEnterTrigger);

Manchmal müssen Sie ein Freezable-Objekt verwenden, das in einer Auflistung oder einem Array enthalten ist. Angenommen, bei einem Rechteck wird eine TransformGroup-Ressource auf die RenderTransform-Eigenschaft angewendet, und Sie möchten eine der Transformationen animieren, die sie enthält.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>  

Um ein in einer Auflistung enthaltenes Freezable-Objekt zu verwenden, verwenden Sie die folgende Pfadsyntax.

(OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex)

Wobei CollectionIndex der Index des Objekts im Array oder in der Auflistung ist.

Um die Angle-Eigenschaft der RotateTransform, der zweiten Transformation in der TransformGroup, zu verwenden, werden der folgende Path und die folgenden PathParameters verwendet.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty, 
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

Das folgende Beispiel enthält den vollständigen Code, um den Angle einer RotateTransform zu animieren, die in einer TransformGroup enthalten ist.

Rectangle rectangle02 = new Rectangle();
rectangle02.Name = "Rectangle02";
this.RegisterName(rectangle02.Name, rectangle02);
rectangle02.Width = 100;
rectangle02.Height = 100;
rectangle02.Fill = Brushes.Blue;
rectangle02.RenderTransform = 
    (TransformGroup)this.Resources["MyTransformGroupResource"];

DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 360;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty, 
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle02.Triggers.Add(myMouseEnterTrigger);

Indirekte Verwendung mit einem Freezable-Objekt als Ausgangspunkt

In den vorhergehenden Abschnitten wurde beschreiben, wie ein Freezable-Objekt indirekt verwendet wird, indem mit einem FrameworkElement oder einem FrameworkContentElement begonnen und eine Eigenschaftenkette zu einer Freezable-Untereigenschaft erstellt wird. Sie können als Ausgangspunkt auch ein Freezable-Objekt verwenden und indirekt eine der Freezable-Untereigenschaften verwenden. Es gilt eine zusätzliche Einschränkung, wenn ein Freezable-Objekt als Ausgangspunkt für die indirekte Verwendung verwendet wird: das erste Freezable-Objekt und jedes Freezable-Objekt, das sich zwischen diesem und der indirekt verwendeten Untereigenschaft befindet, darf nicht fixiert sein.

Interaktives Steuern eines Storyboards in XAML

Zum Starten eines Storyboards in Extensible Application Markup Language (XAML) wird eine BeginStoryboard-Triggeraktion verwendet. Mit BeginStoryboard werden die Animationen an die zu animierenden Objekte und Eigenschaften verteilt und das Storyboard gestartet. (Ausführliche Informationen über diesen Vorgang finden Sie unter Übersicht über das Animations- und Zeitsteuerungssystem.) Wenn Sie BeginStoryboard einen Namen geben, indem Sie die entsprechende Name-Eigenschaft festlegen, wird dieses Storyboard steuerbar. Sie können das Storyboard dann interaktiv steuern, nachdem es gestartet wurde. In der folgenden Liste werden steuerbare Storyboard-Aktionen aufgeführt, die zusammen mit Ereignistriggern zur Steuerung eines Storyboards verwendet werden.

Im folgenden Beispiel werden steuerbare Storyboard-Aktionen zur interaktiven Steuerung eines Storyboards verwendet.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.SDK.Animation.ControllableStoryboardExample"
  WindowTitle="Fading Rectangle Example">
  <StackPanel Margin="10">

    <Rectangle
      Name="MyRectangle"
      Width="100" 
      Height="100"
      Fill="Blue">
    </Rectangle>

    <Button Name="BeginButton">Begin</Button>
    <Button Name="PauseButton">Pause</Button>
    <Button Name="ResumeButton">Resume</Button>
    <Button Name="SkipToFillButton">Skip To Fill</Button>
    <Button Name="StopButton">Stop</Button>

    <StackPanel.Triggers>
      <EventTrigger RoutedEvent="Button.Click" SourceName="BeginButton">
        <BeginStoryboard Name="MyBeginStoryboard">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="MyRectangle" 
              Storyboard.TargetProperty="(Rectangle.Opacity)"
              From="1.0" To="0.0" Duration="0:0:5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="PauseButton">
        <PauseStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="ResumeButton">
        <ResumeStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="SkipToFillButton">
        <SkipStoryboardToFill BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="StopButton">
        <StopStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
    </StackPanel.Triggers>
  </StackPanel>
</Page>

Interaktive Steuerung eines Storyboards mithilfe von Code

In den vorhergehenden Beispielen wurde gezeigt, wie mithilfe von Triggeraktionen Animationen ausgeführt werden. In Code können Sie ebenfalls ein Storyboard mithilfe interaktiver Methoden der Storyboard-Klasse steuern. Um ein Storyboard in Code als interaktiv festzulegen, müssen Sie die entsprechende Überladung der Begin-Methode des Storyboards verwenden und true angeben, damit es sich steuern lässt. Weitere Informationen finden Sie auf der Seite Begin(FrameworkElement, Boolean).

In der folgenden Liste sind die Methoden aufgeführt, mit denen ein Storyboard nach seinem Start bearbeitet werden kann:

Der Vorteil dieser Methoden liegt darin, dass Sie weder ein Trigger-Objekt noch ein TriggerAction-Objekt erstellen müssen. Sie benötigen lediglich einen Verweis auf das steuerbare Storyboard, das Sie bearbeiten möchten.

Hinweis: Alle interaktiven Aktionen, die für eine Clock und somit auch für ein Storyboard ausgeführt werden, erfolgen beim nächsten Teilstrich des Zeitgebermoduls, d. h. kurz vor dem nächsten Rendern. Wenn Sie z. B. mit der Seek-Methode an eine andere Stelle in einer Animation springen, ändert sich der Eigenschaftenwert nicht unmittelbar. Der Wert ändert sich erst beim nächsten Teilstrich des Zeitgebermoduls.

Im folgenden Beispiel wird gezeigt, wie Sie mithilfe der interaktiven Methoden der Storyboard-Klasse Animationen anwenden und steuern können.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SDKSample
{

    public class ControllableStoryboardExample : Page
    {
        private Storyboard myStoryboard;

        public ControllableStoryboardExample()
        {

            // Create a name scope for the page.

            NameScope.SetNameScope(this, new NameScope()); 

            this.WindowTitle = "Controllable Storyboard Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(10);

            // Create a rectangle.
            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";

            // Assign the rectangle a name by 
            // registering it with the page, so that
            // it can be targeted by storyboard
            // animations.
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;
            myStackPanel.Children.Add(myRectangle);

            //
            // Create an animation and a storyboard to animate the
            // rectangle.
            //
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(5000));
            myDoubleAnimation.AutoReverse = true;

            // Create the storyboard.
            myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));

            //
            // Create some buttons to control the storyboard
            // and a panel to contain them.
            //
            StackPanel buttonPanel = new StackPanel();
            buttonPanel.Orientation = Orientation.Horizontal;
            Button beginButton = new Button();
            beginButton.Content = "Begin";
            beginButton.Click += new RoutedEventHandler(beginButton_Clicked);
            buttonPanel.Children.Add(beginButton);
            Button pauseButton = new Button();
            pauseButton.Content = "Pause";
            pauseButton.Click += new RoutedEventHandler(pauseButton_Clicked);
            buttonPanel.Children.Add(pauseButton);
            Button resumeButton = new Button();
            resumeButton.Content = "Resume";
            resumeButton.Click += new RoutedEventHandler(resumeButton_Clicked);
            buttonPanel.Children.Add(resumeButton);
            Button skipToFillButton = new Button();
            skipToFillButton.Content = "Skip to Fill";
            skipToFillButton.Click += new RoutedEventHandler(skipToFillButton_Clicked);
            buttonPanel.Children.Add(skipToFillButton);
            Button setSpeedRatioButton = new Button();
            setSpeedRatioButton.Content = "Triple Speed";
            setSpeedRatioButton.Click += new RoutedEventHandler(setSpeedRatioButton_Clicked);
            buttonPanel.Children.Add(setSpeedRatioButton);
            Button stopButton = new Button();
            stopButton.Content = "Stop";
            stopButton.Click += new RoutedEventHandler(stopButton_Clicked);
            buttonPanel.Children.Add(stopButton);
            myStackPanel.Children.Add(buttonPanel);
            this.Content = myStackPanel;        


        }

        // Begins the storyboard.
        private void beginButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Specifying "true" as the second Begin parameter
            // makes this storyboard controllable.
            myStoryboard.Begin(this, true);

        }

        // Pauses the storyboard.
        private void pauseButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Pause(this);

        }

        // Resumes the storyboard.
        private void resumeButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Resume(this);

        }

        // Advances the storyboard to its fill period.
        private void skipToFillButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.SkipToFill(this);

        }

        // Updates the storyboard's speed.
        private void setSpeedRatioButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(this, 3);

        }

        // Stops the storyboard.
        private void stopButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Stop(this);

        }         

    }

}

Animieren in einem Stil

Sie können mit Storyboard-Objekten Animationen in einem Style definieren. Das Ausführen von Animationen mit einem Storyboard in einem Style ähnelt der Verwendung eines Storyboard-Elements an anderer Stelle, mit den folgenden drei Ausnahmen:

  • Sie geben keinen TargetName an. Das Storyboard verwendet immer das Element, auf das der Style angewendet wird. Um Freezable-Objekte zu verwenden, müssen Sie die indirekte Verwendung benutzen. Weitere Informationen über die indirekte Verwendung finden Sie im Abschnitt Indirekte Verwendung.

  • Sie können keinen SourceName für einen EventTrigger oder einen Trigger angeben.

  • Sie können keine dynamischen Ressourcenverweise oder Datenbindungsausdrücke verwenden, um Storyboard oder Eigenschaftenwerte für Animationen festzulegen. Der Grund liegt darin, dass alles in einem Style threadsicher sein muss, und das Zeitsteuerungssystem muss Storyboard-Objekte mit Freeze fixieren, um sie threadsicher zu machen. Ein Storyboard kann nicht fixiert werden, wenn es selbst oder seine untergeordneten Zeitachsen dynamische Ressourcenverweise oder Datenbindungsausdrücke enthalten. Weitere Informationen über das Fixieren und andere Freezable-Features finden Sie unter Übersicht über Freezable-Objekte.

  • In XAML können Sie keine Ereignishandler für Storyboard oder Animationsereignisse deklarieren.

Ein Beispiel, in dem gezeigt wird, wie ein Storyboard in einem Stil definiert wird, finden Sie unter Gewusst wie: Animieren in einem Stil.

Animieren in einer ControlTemplate

Sie können mit Storyboard-Objekten Animationen in einem ControlTemplate definieren. Das Ausführen von Animationen mit einem Storyboard in einem ControlTemplate ähnelt der Verwendung eines Storyboard an anderer Stelle, mit den folgenden zwei Ausnahmen:

  • Der TargetName darf nur auf untergeordnete Objekte der ControlTemplate verweisen. Wenn TargetName nicht angegeben wird, verwendet die Animation das Element, auf das die ControlTemplate angewendet wird.

  • Der SourceName für einen EventTrigger oder einen Trigger darf nur auf untergeordnete Objekte der ControlTemplate verweisen.

  • Sie können keine dynamischen Ressourcenverweise oder Datenbindungsausdrücke verwenden, um Storyboard oder Eigenschaftenwerte für Animationen festzulegen. Der Grund liegt darin, dass alles in einem ControlTemplate threadsicher sein muss, und das Zeitsteuerungssystem muss Storyboard-Objekte mit Freeze fixieren, um sie threadsicher zu machen. Ein Storyboard kann nicht fixiert werden, wenn es selbst oder seine untergeordneten Zeitachsen dynamische Ressourcenverweise oder Datenbindungsausdrücke enthalten. Weitere Informationen über das Fixieren und andere Freezable-Features finden Sie unter Übersicht über Freezable-Objekte.

  • In XAML können Sie keine Ereignishandler für Storyboard oder Animationsereignisse deklarieren.

Ein Beispiel, in dem gezeigt wird, wie ein Storyboard in einer ControlTemplate definiert wird, finden Sie unter Gewusst wie: Animieren in einer "ControlTemplate".

Animieren bei Änderung eines Eigenschaftenwerts

In Stilen und Steuerelementvorlagen können Sie mit Triggerobjekten ein Storyboard starten, wenn sich eine Eigenschaft ändert. Beispiele finden Sie unter Gewusst wie: Auslösen einer Animation bei Änderung eines Eigenschaftenwerts und Gewusst wie: Animieren in einer "ControlTemplate".

Von Trigger-Eigenschaftenobjekten angewendete Animationen verhalten sich komplexer als EventTrigger-Animationen oder Animationen, die mithilfe von Storyboard-Methoden gestartet wurden. Sie werden mit Animationen "übergeben", die von anderen Trigger-Objekten definiert wurden, setzen sich aber aus EventTrigger und durch Methoden ausgelösten Animationen zusammen.

Siehe auch

Konzepte

Übersicht über Animationen

Übersicht über die Verfahren zur Animation von Eigenschaften

Übersicht über Freezable-Objekte