Freigeben über


Storyboards-Übersicht

In diesem Thema wird gezeigt, wie Sie Mithilfe von Storyboard Objekten Animationen organisieren und anwenden. Es beschreibt, wie man Storyboard-Objekte interaktiv manipuliert und erläutert die Syntax zur indirekten Eigenschaftsansteuerung.

Voraussetzungen

Um dieses Thema zu verstehen, sollten Sie mit den verschiedenen Animationstypen und deren grundlegenden Features vertraut sein. Eine Einführung in die Animation finden Sie in der Animationsübersicht. Außerdem sollten Sie wissen, wie angefügte Eigenschaften verwendet werden. Weitere Informationen zu angefügten Eigenschaften finden Sie in der Übersicht über angefügte Eigenschaften.

Was ist ein Storyboard?

Animationen sind nicht die einzigen nützlichen Arten von Zeitleisten. Andere Zeitachsenklassen werden bereitgestellt, um Ihnen beim Organisieren von Zeitachsensätzen zu helfen und Zeitachsen auf Eigenschaften anzuwenden. Containerzeitachsen werden von der TimelineGroup Klasse abgeleitet und enthalten ParallelTimeline und Storyboard.

Ein Storyboard ist eine Art Container-Zeitachse, die Zielinformationen für die darin enthaltenen Zeitachsen bereitstellt. Ein Storyboard kann jeden Beliebigen Typ Timelineenthalten, einschließlich anderer Containerzeitachsen und Animationen. Storyboard Mit Objekten können Sie Zeitachsen kombinieren, die sich auf eine Vielzahl von Objekten und Eigenschaften in einer einzelnen Zeitbaumstruktur auswirken, wodurch komplexe Zeitverhalten leicht organisiert und gesteuert werden kann. Angenommen, Sie möchten eine Schaltfläche, die diese drei Dinge ausführt.

  • Vergrößern und Ändern der Farbe, wenn der Benutzer die Schaltfläche auswählt.

  • Beim Klicken schrumpfen und dann auf die ursprüngliche Größe zurückwachsen.

  • Verkleinern und Verblassen auf 50 Prozent Deckkraft, wenn sie deaktiviert wird.

In diesem Fall haben Sie mehrere Animationssätze, die für dasselbe Objekt gelten, und möchten sie zu unterschiedlichen Zeiten abspielen, abhängig vom Zustand des Buttons. Storyboard Mit Objekten können Sie Animationen organisieren und in Gruppen auf ein oder mehrere Objekte anwenden.

Wo können Sie ein Storyboard verwenden?

Eine Storyboard kann verwendet werden, um Abhängigkeitseigenschaften von animierbaren Klassen zu animieren (weitere Informationen dazu, was eine Klasse animierbar macht, finden Sie in der Animationsübersicht). Da Storyboarding jedoch ein Feature auf Frameworkebene ist, muss das Objekt zu einem NameScope oder einem FrameworkElement oder FrameworkContentElement gehören.

Sie könnten z. B. die Storyboard verwenden, um Folgendes zu tun:

Sie konnten jedoch kein Storyboard verwenden, um ein SolidColorBrush zu animieren, das seinen Namen nicht bei einem FrameworkElement oder FrameworkContentElement registriert hat oder nicht verwendet wurde, um eine Eigenschaft eines FrameworkElement oder FrameworkContentElement festzulegen.

Anwenden von Animationen mit einem Storyboard

Um Storyboard zu verwenden, um Animationen zu organisieren und anzuwenden, fügen Sie die Animationen als untergeordnete Zeitachsen von Storyboard hinzu. Die Storyboard Klasse stellt die Storyboard.TargetName und Storyboard.TargetProperty angefügten Eigenschaften bereit. Sie legen diese Eigenschaften für eine Animation fest, um das Zielobjekt und die Zieleigenschaft anzugeben.

Um Animationen auf ihre Ziele anzuwenden, beginnen Sie mit der Storyboard Verwendung einer Triggeraktion oder einer Methode. In XAML verwenden Sie ein BeginStoryboard Objekt mit einem EventTrigger, Triggeroder DataTrigger. Im Code können Sie auch die Begin Methode verwenden.

In der folgenden Tabelle sind die verschiedenen Stellen aufgeführt, an denen jede jeweilige Storyboard Begin-Technik unterstützt wird: pro Instanz, Stil, Steuerelementvorlage und Datenvorlage. "Pro Instanz" bezieht sich auf die Technik, eine Animation oder ein Storyboard direkt auf Instanzen eines Objekts anzuwenden, anstatt in einer Formatvorlage, Steuerelementvorlage oder Datenvorlage.

Die Arbeit mit dem Storyboard beginnt... Pro Instanz Stil Steuerelementvorlage Datenvorlage Beispiel
BeginStoryboard und ein EventTrigger Ja Ja Ja Ja Animieren einer Eigenschaft mithilfe eines Storyboards
BeginStoryboard und eine Eigenschaft Trigger Nein Ja Ja Ja Auslösen einer Animation, wenn sich ein Eigenschaftswert ändert
BeginStoryboard und eine Eigenschaft MultiTrigger Nein Ja Ja Ja Beispiel für eine MultiTrigger-Klasse
BeginStoryboard und a DataTrigger Nein Ja Ja Ja Vorgehensweise: Auslösen einer Animation beim Ändern von Daten
BeginStoryboard und a MultiDataTrigger Nein Ja Ja Ja Beispiel für multiDataTrigger-Klasse
Begin-Methode Ja Nein Nein Nein Animieren einer Eigenschaft mithilfe eines Storyboards

Im folgenden Beispiel wird ein Storyboard verwendet, um die Width eines Rectangle-Elements und die Color eines SolidColorBrush, das zum Malen dieses Rectangle verwendet wird, zu animieren.

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://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.

Targeting Framework-Elemente, Framework-Inhaltselemente und Einfrierbare Objekte

Im vorherigen Abschnitt wurde erwähnt, dass eine Animation, um ihr Ziel zu finden, den Namen des Ziels und die zu animierende Eigenschaft kennen muss. Die Angabe der zu animierenden Eigenschaft ist einfach: Legen Sie einfach den Namen der zu animierenden Eigenschaft fest TargetProperty. Sie geben den Namen des Objekts an, dessen Eigenschaft Sie animieren möchten, indem Sie die Storyboard.TargetName Eigenschaft für die Animation festlegen.

Vorsicht

Sie können die Target Eigenschaft zwar verwenden, um eine direkte Bindung an ein Objekt als Alternative zu TargetNameerstellen, dies ist jedoch nicht serialisierbar. Es ist nicht garantiert, dass das Target Objekt in XAML korrekt referenziert werden kann.

Damit die TargetName Eigenschaft funktioniert, muss das zielorientierte Objekt einen Namen haben. Das Zuweisen eines Namens zu einem FrameworkElement oder einem FrameworkContentElement in XAML unterscheidet sich von dem Zuweisen eines Namens zu einem Freezable Objekt.

Framework-Elemente sind jene Klassen, die von der Klasse FrameworkElement erben. Beispiele für Framework-Elemente sind Window: , DockPanel, , Buttonund Rectangle. Im Wesentlichen sind alle Fenster, Panels und Steuerelemente Elemente. Framework-Inhaltselemente sind die Klassen, die von der Klasse FrameworkContentElement erben. Beispiele für Framework-Inhaltselemente sind u. a FlowDocumentParagraph. Wenn Sie nicht sicher sind, ob es sich bei einem Typ um ein Frameworkelement oder ein Framework-Inhaltselement handelt, überprüfen Sie, ob er über eine Name-Eigenschaft verfügt. Wenn dies der Fall ist, handelt es sich wahrscheinlich um ein Frameworkelement oder ein Framework-Inhaltselement. Überprüfen Sie unbedingt den Abschnitt "Vererbungshierarchie" der Typseite.

Um die Zielbestimmung eines Frameworkelements oder eines Frameworkinhaltselements in XAML zu aktivieren, legen Sie dessen Name Eigenschaft fest. Im Code müssen Sie auch die RegisterName-Methode verwenden, um den Namen des Elements bei dem Element zu registrieren, für das Sie ein NameScope erstellt haben.

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

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

Nachdem ein Name vorhanden ist, 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. Beispiele für Freezable schließen SolidColorBrush, RotateTransform und GradientStop ein.

Um die Zielbestimmung einer Freezable animation in XAML zu aktivieren, verwenden Sie die x:Name-Direktive , um sie einem Namen zuzuweisen. Im Code verwenden Sie die RegisterName-Methode, um seinen Namen bei dem Element zu registrieren, für das Sie ein 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 von einer Animation adressiert 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 verwenden Namensbereiche, um die TargetName Eigenschaft aufzulösen. Weitere Informationen zu WPF-Namenbereichen finden Sie unter WPF-XAML-NameScopes. Wenn die Eigenschaft nicht angegeben wird, zielt die TargetName Animation auf das Element ab, für das sie definiert ist, oder im Falle von Formatvorlagen das formatierte Element.

Manchmal kann einem Freezable Objekt kein Name zugewiesen werden. Wenn beispielsweise ein Objekt Freezable als Ressource deklariert oder zum Festlegen eines Eigenschaftswerts in einer Formatvorlage verwendet wird, kann er keinen Namen erhalten. Da es keinen Namen hat, kann es nicht direkt anvisiert werden, sie kann aber indirekt anvisiert werden. In den folgenden Abschnitten wird beschrieben, wie indirekte Zielbestimmung verwendet wird.

Indirekte Zielbestimmung

Es gibt Fälle, in denen ein Freezable nicht direkt von einer Animation angesprochen werden kann, zum Beispiel wenn Freezable als Ressource deklariert oder zur Festlegung eines Wertes in einem Stil verwendet wird. In diesen Fällen, auch wenn Sie es nicht direkt als Ziel festlegen können, können Sie das Objekt Freezable trotzdem animieren. Statt die TargetName Eigenschaft mit dem Namen des Freezable Elements festzulegen, geben Sie ihm den Namen des Elements, dem das Freezable „zugehört.“ Beispielsweise gehört ein SolidColorBrush, das verwendet wird, um die Fill eines Rechteckelements festzulegen, zu diesem Rechteck. Zum Animieren des Pinsels würden Sie die Animation des TargetProperty mit einer Kette von Eigenschaften festlegen, die bei der Eigenschaft des Frameworkelements oder Framework-Inhaltselements beginnt, mit der Freezable festgelegt wurde, und mit der Eigenschaft Freezable endet, die animiert werden soll.

<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, wenn der Freezable eingefroren ist, ein Klon erstellt wird und dieser Klon animiert wird. In diesem Fall gibt die Eigenschaft des HasAnimatedProperties ursprünglichen Objekts weiterhin zurück false, da das ursprüngliche Objekt nicht tatsächlich animiert ist. Weitere Informationen zum Klonen finden Sie unter " Freezable Objects Overview".

Beachten Sie außerdem, dass bei Verwendung der indirekten Eigenschaftenadressierung objekte, die nicht vorhanden sind, als Ziel verwendet werden können. Angenommen, Sie vermuten, dass das Background einer bestimmten Schaltfläche mit einem SolidColorBrush gesetzt wurde und versuchen, dessen Farbe zu animieren, obwohl tatsächlich ein LinearGradientBrush verwendet wurde, um den Hintergrund der Schaltfläche festzulegen. 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 werden die Syntax für indirekte Eigenschaftenadressierung ausführlicher beschrieben.

Indirektes Anvisieren einer Eigenschaft eines Freezable in XAML

Verwenden Sie die folgende Syntax, um eine Eigenschaft einer freizierbaren Eigenschaft in XAML zu verwenden.

Eigenschaftssyntax
ElementPropertyName.FreezablePropertyName

Wobei

  • ElementPropertyName ist die Eigenschaft des FrameworkElement, die durch das Freezable festgelegt wird, und

  • FreezablePropertyName ist die Eigenschaft der Freezable, die animiert werden soll.

Im folgenden Code wird gezeigt, wie der Color eines SolidColorBrush animiert wird, der verwendet wird, um das Fill eines Rechteckelements festzulegen.

<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 auf ein Freezable zugreifen, das in einer Sammlung oder einem Array enthalten ist.

Verwenden Sie die folgende Pfadsyntax, um ein innerhalb einer Sammlung enthaltenes freizierbares Element anzusprechen.

Pfadsyntax
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Dabei ist CollectionIndex der Index des Objekts in seinem Array oder seiner Auflistung.

Angenommen, ein Rechteck hat eine TransformGroup Ressource auf seine RenderTransform Eigenschaft angewendet, und Sie möchten eine der darin enthaltenen Transformationen animieren.

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

Der folgende Code zeigt, wie die Eigenschaft Angle des im vorherigen Beispiel gezeigten RotateTransform 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>  

Indirektes Ausrichten einer Eigenschaft eines Freezable-Elementes im Code

Im Code erstellen Sie ein PropertyPath Objekt. Wenn Sie das PropertyPath Objekt erstellen, geben Sie ein Path und PathParameters.

Um PathParameters zu erstellen, erzeugen Sie ein Array vom Typ DependencyProperty, das eine Liste der Felder der Abhängigkeitseigenschaftsbezeichner enthält. Das erste Bezeichnerfeld ist für die Eigenschaft der FrameworkElement oder FrameworkContentElement, die Freezable zum Festlegen verwendet wird. Das nächste Kennzeichnungsfeld gibt die zu fokussierende Eigenschaft von Freezable an. Stellen Sie es sich als eine Kette von Eigenschaften vor, die das Freezable mit dem FrameworkElement Objekt verbindet.

Im Folgenden sehen Sie ein Beispiel für eine Abhängigkeitseigenschaftskette, die auf das Color eines SolidColorBrush abzielt, um die Fill eines Rechteckelements festzulegen.

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

Sie müssen zusätzlich auch eine Path angeben. Ein Path ist ein String, der dem Path angibt, wie es seine PathParameters interpretieren soll. Es verwendet die folgende Syntax.

Syntax des Eigenschaftspfads
( OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Wobei

  • OwnerPropertyArrayIndex ist der Index des DependencyProperty Arrays, der den Bezeichner der FrameworkElement Eigenschaft des Objekts enthält, die Freezable zum Festlegen verwendet wird, und

  • FreezablePropertyArrayIndex ist der Index des DependencyProperty Arrays, das den Bezeichner der eigenschaft enthält, die als Ziel dient.

Im folgenden Beispiel wird das Path gezeigt, das das im vorherigen Beispiel definierte PathParameters begleitet.

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

Das folgende Beispiel kombiniert den Code aus den vorherigen Beispielen, um das Color eines SolidColorBrush zum Festlegen des Fill eines Rechteckelements zu animieren.


// 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 auf ein Freezable zugreifen, das in einer Sammlung oder einem Array enthalten ist. Angenommen, ein Rechteck hat eine TransformGroup Ressource auf seine RenderTransform Eigenschaft angewendet, und Sie möchten eine der darin enthaltenen Transformationen animieren.

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

Um ein Freezable, die in einer Sammlung enthalten ist, anzusprechen, nutzen Sie die folgende Pfadsyntax.

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

Dabei ist CollectionIndex der Index des Objekts in seinem Array oder seiner Auflistung.

Um die Angle-Eigenschaft von RotateTransform zu beeinflussen, indem Sie die zweite Transformation in TransformGroup gezielt einsetzen, verwenden Sie das folgende Path und PathParameters.

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 zeigt den vollständigen Code zur Animation des Angle, das in einem RotateTransform innerhalb eines 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);

Indirektes Targeting unter Verwendung eines Freezable als Ausgangspunkt

In den vorherigen Abschnitten wird beschrieben, wie Sie indirekt auf ein Freezable abzielen können, indem Sie mit einem FrameworkElement oder FrameworkContentElement beginnen und eine Eigenschaftskette zu einer Freezable-Untereigenschaft erstellen. Sie können auch einen Freezable als Ausgangspunkt verwenden und indirekt auf eine seiner Freezable Untereigenschaften abzielen. Eine zusätzliche Einschränkung gilt, wenn ein Freezable als Ausgangspunkt für die indirekte Zielbestimmung verwendet wird: Der Startpunkt Freezable und jedes Freezable zwischen ihm und der indirekt anvisierten Untereigenschaft darf nicht eingefroren sein.

Interaktives Steuern eines Storyboards in XAML

Um ein Storyboard in Extensible Application Markup Language (XAML) zu starten, verwenden Sie eine BeginStoryboard Triggeraktion. BeginStoryboard verteilt die Animationen auf die Objekte und Eigenschaften, die animiert werden, und startet das Storyboard. (Ausführliche Informationen zu diesem Prozess finden Sie unter " Animation and Timing System Overview".) Wenn Sie dem BeginStoryboard Namen einen Namen geben, indem Sie dessen Name Eigenschaft angeben, machen Sie ihn zu einem steuerbaren Storyboard. Anschließend können Sie das Storyboard interaktiv steuern, nachdem es gestartet wurde. Es folgt eine Liste der steuerbaren Storyboardaktionen, die Sie mit Ereignistriggern zum Steuern eines Storyboards verwenden.

Im folgenden Beispiel werden steuerbare Storyboardaktionen verwendet, um ein Storyboard interaktiv zu steuern.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>

Interaktives Steuern eines Storyboards mithilfe von Code

In den vorherigen Beispielen wurde gezeigt, wie Sie mithilfe von Triggeraktionen animieren. Im Code können Sie auch ein Storyboard mithilfe interaktiver Methoden der Storyboard Klasse steuern. Damit es Storyboard im Code interaktiv gemacht werden kann, müssen Sie die entsprechende Überladung der Storyboardmethode Begin verwenden und true angeben, um es steuerbar zu machen. Weitere Informationen finden Sie auf der Begin(FrameworkElement, Boolean) Seite.

Die folgende Liste zeigt die Methoden, mit denen ein Storyboard nach dem Start manipuliert werden kann.

Der Vorteil bei der Verwendung dieser Methoden besteht darin, dass Sie nicht Trigger oder TriggerAction Objekte erstellen müssen. Sie benötigen lediglich einen Verweis auf das kontrollierbare Storyboard, das Sie bearbeiten möchten.

Hinweis

Alle interaktiven Aktionen, die auf einem Clock und daher auch auf einem Storyboard durchgeführt werden, erfolgen beim nächsten Tick der Timing-Engine, der kurz vor dem nächsten Rendern stattfindet. Wenn Sie z. B. die Seek Methode verwenden, um zu einem anderen Punkt in einer Animation zu springen, ändert sich der Eigenschaftswert nicht sofort, sondern erst beim nächsten Tick der Timing-Engine.

Das folgende Beispiel zeigt, wie Animationen mithilfe der interaktiven Methoden der Storyboard Klasse angewendet und gesteuert werden.

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);
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Shapes
Imports System.Windows.Media
Imports System.Windows.Media.Animation

Namespace SDKSample

    Public Class ControllableStoryboardExample
        Inherits Page
        Private myStoryboard As Storyboard

        Public Sub New()

            ' Create a name scope for the page.

            NameScope.SetNameScope(Me, New NameScope())

            Me.WindowTitle = "Controllable Storyboard Example"
            Dim myStackPanel As New StackPanel()
            myStackPanel.Margin = New Thickness(10)

            ' Create a rectangle.
            Dim myRectangle As 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.
            Me.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.
            '
            Dim myDoubleAnimation As 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.
            '
            Dim buttonPanel As New StackPanel()
            buttonPanel.Orientation = Orientation.Horizontal
            Dim beginButton As New Button()
            beginButton.Content = "Begin"
            AddHandler beginButton.Click, AddressOf beginButton_Clicked
            buttonPanel.Children.Add(beginButton)
            Dim pauseButton As New Button()
            pauseButton.Content = "Pause"
            AddHandler pauseButton.Click, AddressOf pauseButton_Clicked
            buttonPanel.Children.Add(pauseButton)
            Dim resumeButton As New Button()
            resumeButton.Content = "Resume"
            AddHandler resumeButton.Click, AddressOf resumeButton_Clicked
            buttonPanel.Children.Add(resumeButton)
            Dim skipToFillButton As New Button()
            skipToFillButton.Content = "Skip to Fill"
            AddHandler skipToFillButton.Click, AddressOf skipToFillButton_Clicked
            buttonPanel.Children.Add(skipToFillButton)
            Dim setSpeedRatioButton As New Button()
            setSpeedRatioButton.Content = "Triple Speed"
            AddHandler setSpeedRatioButton.Click, AddressOf setSpeedRatioButton_Clicked
            buttonPanel.Children.Add(setSpeedRatioButton)
            Dim stopButton As New Button()
            stopButton.Content = "Stop"
            AddHandler stopButton.Click, AddressOf stopButton_Clicked
            buttonPanel.Children.Add(stopButton)
            myStackPanel.Children.Add(buttonPanel)
            Me.Content = myStackPanel


        End Sub

        ' Begins the storyboard.
        Private Sub beginButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Specifying "true" as the second Begin parameter
            ' makes this storyboard controllable.
            myStoryboard.Begin(Me, True)

        End Sub

        ' Pauses the storyboard.
        Private Sub pauseButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Pause(Me)

        End Sub

        ' Resumes the storyboard.
        Private Sub resumeButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Resume(Me)

        End Sub

        ' Advances the storyboard to its fill period.
        Private Sub skipToFillButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.SkipToFill(Me)

        End Sub

        ' Updates the storyboard's speed.
        Private Sub setSpeedRatioButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(Me, 3)

        End Sub

        ' Stops the storyboard.
        Private Sub stopButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Stop(Me)

        End Sub

    End Class

End Namespace

Animieren in einem Stil

Sie können Storyboard-Objekte verwenden, um Animationen in einem Style zu definieren. Das Animieren mit einem Storyboard in einem Style ähnelt der Verwendung eines Storyboard an anderen Stellen, mit den folgenden drei Ausnahmen:

  • Sie geben kein TargetName an; das Storyboard Element zielt immer auf das Element ab, auf das Style angewendet wird. Um Freezable-Objekte zu erfassen, müssen Sie das indirekte Zielen verwenden. Weitere Informationen zur indirekten Zielbestimmung finden Sie im Abschnitt "Indirekte Zielbestimmung ".

  • Sie können keinen SourceName für ein EventTrigger oder ein Trigger spezifizieren.

  • Sie können keine dynamischen Ressourcenverweise oder Datenbindungsausdrücke verwenden, um Storyboard oder Animationseigenschaften festzulegen. Das liegt daran, dass alles innerhalb eines Style Threads sicher sein muss und das Timing-System Objekte benötigt FreezeStoryboard , um sie threadsicher zu machen. Eine Storyboard kann nicht eingefroren werden, wenn sie oder ihre untergeordneten Zeitachsen dynamische Ressourcenverweise oder Datenbindungsausdrücke enthalten. Weitere Informationen zum Einfrieren und anderen Freezable Features finden Sie in der Übersicht über Freezable Objects.

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

Ein Beispiel zum Definieren eines Storyboards in einem Stil finden Sie im Beispiel "Animieren in einem Stil".

Animieren in einer ControlTemplate

Sie können Storyboard-Objekte verwenden, um Animationen in einem ControlTemplate zu definieren. Das Animieren mit einem Storyboard in einem ControlTemplate ähnelt der Verwendung eines Storyboard anderswo, mit den folgenden beiden Ausnahmen:

  • Das TargetName darf sich nur auf untergeordnete Objekte des ControlTemplate beziehen. Wenn TargetName nicht angegeben, zielt die Animation auf das Element ab, auf das die ControlTemplate Animation angewendet wird.

  • Das SourceName für ein EventTrigger oder ein Trigger kann nur auf untergeordnete Objekte der ControlTemplate verweisen.

  • Sie können keine dynamischen Ressourcenverweise oder Datenbindungsausdrücke verwenden, um Storyboard oder Animationseigenschaften festzulegen. Das liegt daran, dass alles innerhalb eines ControlTemplate Threads sicher sein muss und das Timing-System Objekte benötigt FreezeStoryboard , um sie threadsicher zu machen. Eine Storyboard kann nicht eingefroren werden, wenn sie oder ihre untergeordneten Zeitachsen dynamische Ressourcenverweise oder Datenbindungsausdrücke enthalten. Weitere Informationen zum Einfrieren und anderen Freezable Features finden Sie in der Übersicht über Freezable Objects.

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

Ein Beispiel, das zeigt, wie ein Storyboard in einem ControlTemplate definiert wird, finden Sie im Beispiel Animate in einem ControlTemplate.

Eine Animation ausführen, wenn sich ein Eigenschaftswert ändert

In Formatvorlagen und Steuerelementvorlagen können Sie Trigger-Objekte verwenden, um ein Storyboard zu starten, wenn sich eine Eigenschaft ändert. Beispiele finden Sie unter Trigger an Animation When a Property Value Changes and Animate in a ControlTemplate.

Animationen, die von Eigenschaftsobjekten Trigger angewendet werden, verhalten sich komplexer als EventTrigger Animationen oder Animationen, die mit Storyboard Methoden begonnen haben. Sie übergeben mit Animationen, die von anderen Trigger-Objekten definiert wurden, aber in Verbindung mit EventTrigger und durch Methoden ausgelösten Animationen.

Siehe auch