Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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:
Animieren eines SolidColorBrush (Nicht-Framework-Elements), das den Hintergrund einer Schaltfläche (eine Art von FrameworkElement) zeichnet
Animieren Eines SolidColorBrush (Nicht-Framework-Elements), das die Füllung eines GeometryDrawing (Nicht-Framework-Elements) zeichnet, das mit einem Image (FrameworkElement) angezeigt wird.
Animieren Sie im Code ein SolidColorBrush, das von einer Klasse deklariert wird, die auch ein FrameworkElement enthält, falls SolidColorBrush seinen Namen bei diesem FrameworkElement registriert hat.
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.
PauseStoryboard: Hält das Storyboard an.
ResumeStoryboard: Setzt ein angehaltenes Storyboard fort.
SetStoryboardSpeedRatio: Ändert die Geschwindigkeit des Storyboards.
SkipStoryboardToFill: Führt ein Storyboard bis zum Ende seines Füllzeitraums aus, wenn es einen hat.
StopStoryboard: Stoppt das Storyboard.
RemoveStoryboard: Entfernt das Storyboard.
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
.NET Desktop feedback