Storyboards Overview

This topic shows how to use Storyboard objects to organize and apply animations. It describes how to interactively manipulate Storyboard objects and describes indirect property targeting syntax.

To understand this topic, you should be familiar with the different animation types and their basic features. For an introduction to animation, see the Animation Overview. You should also know how to use attached properties. For more information about attached properties, see the Attached Properties Overview.

Animations are not the only useful type of timeline. Other timeline classes are provided to help you organize sets of timelines, and to apply timelines to properties. Container timelines derive from the TimelineGroup class, and include ParallelTimeline and Storyboard.

A Storyboard is a type of container timeline that provides targeting information for the timelines it contains. A Storyboard can contain any type of Timeline, including other container timelines and animations. Storyboard objects enable you to combine timelines that affect a variety of objects and properties into a single timeline tree, making it easy to organize and control complex timing behaviors. For example, suppose you want a button that does these three things.

  • Grow and change color when the user selects the button.

  • Shrink away and then grow back to its original size when clicked.

  • Shrink and fade to 50 percent opacity when it becomes disabled.

In this case, you have multiple sets of animations that apply to the same object, and you want to play at different times, dependent on the state of the button. Storyboard objects enable you to organize animations and apply them in groups to one or more objects.

A Storyboard can be used to animate dependency properties of animatable classes (for more information about what makes a class animatable, see the Animation Overview). However, because storyboarding is a framework-level feature, the object must belong to the NameScope of a FrameworkElement or a FrameworkContentElement.

For example, you could use a Storyboard to do the following:

However, you could not use a Storyboard to animate a SolidColorBrush that did not register its name with a FrameworkElement or FrameworkContentElement, or was not used to set a property of a FrameworkElement or FrameworkContentElement.

To use a Storyboard to organize and apply animations, you add the animations as child timelines of the Storyboard. The Storyboard class provides the Storyboard.TargetName and Storyboard.TargetProperty attached properties. You set these properties on an animation to specify its target object and property.

To apply animations to their targets, you begin the Storyboard using a trigger action or a method. In XAML, you use a BeginStoryboard object with an EventTriggerTrigger, or DataTrigger. In code, you can also use the Begin method.

The following table shows the different places where each Storyboard begin technique is supported: per-instance, style, control template, and data template. "Per-Instance" refers to the technique of applying an animation or storyboard directly to instances of an object, rather than in a style, control template, or data template.

Storyboard is begun using…

Per-instance

Style

Control template

Data template

Example

BeginStoryboard and an EventTrigger

Yes

Yes

Yes

Yes

How to: Animate a Property by Using a Storyboard

BeginStoryboard and a property Trigger

No

Yes

Yes

Yes

How to: Trigger an Animation When a Property Value Changes

BeginStoryboard and a DataTrigger

No

Yes

Yes

Yes

How to: Trigger an Animation When Data Changes

Begin method

Yes

No

No

No

How to: Animate a Property by Using a Storyboard

The following example uses a Storyboard to animate the Width of a Rectangle element and the Color of a SolidColorBrush used to paint that Rectangle.

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

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


Namespace Microsoft.Samples.Animation
	Public Class StoryboardsExample
		Inherits Page
		Public Sub New()
			Me.WindowTitle = "Storyboards Example"
			Dim myStackPanel As New StackPanel()
			myStackPanel.Margin = New Thickness(20)

			Dim myRectangle As New Rectangle()
			myRectangle.Name = "MyRectangle"

			' Create a name scope for the page.
			NameScope.SetNameScope(Me, New NameScope())

			Me.RegisterName(myRectangle.Name, myRectangle)
			myRectangle.Width = 100
			myRectangle.Height = 100
			Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
			Me.RegisterName("MySolidColorBrush", mySolidColorBrush)
			myRectangle.Fill = mySolidColorBrush

			Dim myDoubleAnimation As 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))

			Dim myColorAnimation As 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))
			Dim myStoryboard As New Storyboard()
			myStoryboard.Children.Add(myDoubleAnimation)
			myStoryboard.Children.Add(myColorAnimation)

			AddHandler myRectangle.MouseEnter, Sub(sender As Object, e As MouseEventArgs) myStoryboard.Begin(Me)

			myStackPanel.Children.Add(myRectangle)
			Me.Content = myStackPanel
		End Sub
	End Class
End Namespace

The following sections describe the TargetName and TargetProperty attached properties in more detail.

The previous section mentioned that, for an animation to find its target, it must know the target's name and the property to animate. Specifying the property to animate is straight forward: simply set Storyboard.TargetProperty with the name of the property to animate. You specify the name of the object whose property you want to animate by setting the Storyboard.TargetName property on the animation.

For the TargetName property to work, the targeted object must have a name. Assigning a name to a FrameworkElement or a FrameworkContentElement in XAML is different than assigning a name to a Freezable object.

Framework elements are those classes that inherit from the FrameworkElement class. Examples of framework elements include Window, DockPanel, Button, and Rectangle. Essentially all windows, panels, and controls are elements. Framework content elements are those classes that inherit from the FrameworkContentElement class. Examples of framework content elements include FlowDocument and Paragraph. If you're not sure whether a type is a framework element or a framework content element, check to see whether it has a Name property. If it does, it's probably a framework element or a framework content element. To be sure, check the InheritanceHierarchy section of its type page.

To enable the targeting of a framework element or a framework content element in XAML, you set its Name property. In code, you also need to use the RegisterName method to register the element's name with the element for which you've created a NameScope.

The following example, taken from the preceding example, assigns the name MyRectangle a Rectangle, a type of FrameworkElement.

<Rectangle Name="MyRectangle"
  Width="100"
  Height="100">
			Dim myRectangle As New Rectangle()
			myRectangle.Name = "MyRectangle"

			' Create a name scope for the page.
			NameScope.SetNameScope(Me, New NameScope())

			Me.RegisterName(myRectangle.Name, myRectangle)

After it has a name, you can animate a property of that element.

<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 types are those classes that inherit from the Freezable class. Examples of Freezable include SolidColorBrush, RotateTransform, and GradientStop.

To enable the targeting of a Freezable by an animation in XAML, you use the x:Name Directive to assign it a name. In code, you use the RegisterName method to register its name with the element for which you've created a NameScope.

The following example assigns a name to a Freezable object.

<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
			Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
			Me.RegisterName("MySolidColorBrush", mySolidColorBrush)

The object can then be targeted by an animation.

<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 objects use name scopes to resolve the TargetName property. For more information about WPF name scopes, see WPF XAML Namescopes. If the TargetName property is omitted, the animation targets the element on which it is defined, or, in the case of styles, the styled element.

Sometimes a name can't be assigned to a Freezable object. For example, if a Freezable is declared as a resource or used to set a property value in a style, it can't be given a name. Because it doesn't have a name, it can't be targeted directly—but it can be targeted indirectly. The following sections describe how to use indirect targeting.

There are times a Freezable can't be targeted directly by an animation, such as when the Freezable is declared as a resource or used to set a property value in a style. In these cases, even though you can't target it directly, you can still animate the Freezable object. Instead of setting the TargetName property with the name of the Freezable, you give it the name of the element to which the Freezable "belongs." For example, a SolidColorBrush used to set the Fill of a rectangle element belongs to that rectangle. To animate the brush, you would set the animation's TargetProperty with a chain of properties that starts at the property of the framework element or framework content element the Freezable was used to set and ends with the Freezable property to animate.

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

Note that, if the Freezable is frozen, a clone will be made, and that clone will be animated. When this happens, the original object's HasAnimatedProperties property continues to return false, because the original object is not actually animated. For more information about cloning, see the Freezable Objects Overview.

Also note that, when using indirect property targeting, it's possible to target objects that don't exist. For example, you might assume that the Background of a particular button was set with a SolidColorBrush and try to animate its Color, when in fact a LinearGradientBrush was used to set the button's Background. In these cases, no exception is thrown; the animation fails to have a visible effect because LinearGradientBrush does not react to changes to the Color property.

The following sections describe indirect property targeting syntax in more detail.

To target a property of a freezable in XAML, use the following syntax.

ElementPropertyName.FreezablePropertyName

Where

The following code shows how to animate the Color of a SolidColorBrush used to set the

Fill of a rectangle element.

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

Sometimes you need to target a freezable contained in a collection or array.

To target a freezable contained in a collection, you use the following path syntax.

ElementPropertyName .Children[ CollectionIndex ]. FreezablePropertyName

Where CollectionIndex is the index of the object in its array or collection.

For example, suppose that a rectangle has a TransformGroup resource applied to its RenderTransform property, and you want to animate one of the transforms it contains.

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

The following code shows how to animate the Angle property of the RotateTransform shown in the previous example.

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

In code, you create a PropertyPath object. When you create the PropertyPath, you specify a Path and PathParameters.

To create PathParameters, you create an array of type DependencyProperty that contains a list of dependency property identifier fields. The first identifier field is for the property of the FrameworkElement or FrameworkContentElement that the Freezable is used to set. The next identifier field represents the property of the Freezable to target. Think of it as a chain of properties that connects the Freezable to the FrameworkElement object.

The following is an example of a dependency property chain that targets the Color of a SolidColorBrush used to set the Fill of a rectangle element.

			Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}

You also need to specify a Path. A Path is a String that tells the Path how to interpret its PathParameters. It uses the following syntax.

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Where

  • OwnerPropertyArrayIndex is the index of the DependencyProperty array that contains the identifier of the FrameworkElement object's property that the Freezable is used to set, and

  • FreezablePropertyArrayIndex is the index of the DependencyProperty array that contains the identifier of property to target.

The following example shows the Path that would accompany the PathParameters defined in the preceding example.

			Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
			Dim thePath As String = "(0).(1)"

The following example combines the code in the previous examples to animate the Color of a SolidColorBrush used to set the Fill of a rectangle element.


			' Create a name scope for the page.
			NameScope.SetNameScope(Me, New NameScope())

			Dim rectangle01 As New Rectangle()
			rectangle01.Name = "Rectangle01"
			Me.RegisterName(rectangle01.Name, rectangle01)
			rectangle01.Width = 100
			rectangle01.Height = 100
			rectangle01.Fill = CType(Me.Resources("MySolidColorBrushResource"), SolidColorBrush)

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

			Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
			Dim thePath As String = "(0).(1)"
			Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
			Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath)

			Dim myStoryboard As New Storyboard()
			myStoryboard.Children.Add(myColorAnimation)
			Dim myBeginStoryboard As New BeginStoryboard()
			myBeginStoryboard.Storyboard = myStoryboard
			Dim myMouseEnterTrigger As New EventTrigger()
			myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
			myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
			rectangle01.Triggers.Add(myMouseEnterTrigger)

Sometimes you need to target a freezable contained in a collection or array. For example, suppose that a rectangle has a TransformGroup resource applied to its RenderTransform property, and you want to animate one of the transforms it contains.

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

To target a Freezable contained in a collection, you use the following path syntax.

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

Where CollectionIndex is the index of the object in its array or collection.

To target the Angle property of the RotateTransform, the second transform in the TransformGroup, you would use the following Path and PathParameters.

			Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
			Dim thePath As String = "(0).(1)[1].(2)"
			Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
			Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)

The following example shows the complete code for animating the Angle of a RotateTransform contained within a TransformGroup.

			Dim rectangle02 As New Rectangle()
			rectangle02.Name = "Rectangle02"
			Me.RegisterName(rectangle02.Name, rectangle02)
			rectangle02.Width = 100
			rectangle02.Height = 100
			rectangle02.Fill = Brushes.Blue
			rectangle02.RenderTransform = CType(Me.Resources("MyTransformGroupResource"), TransformGroup)

			Dim myDoubleAnimation As New DoubleAnimation()
			myDoubleAnimation.From = 0
			myDoubleAnimation.To = 360
			myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(1))
			Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name)

			Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
			Dim thePath As String = "(0).(1)[1].(2)"
			Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
			Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)

			Dim myStoryboard As New Storyboard()
			myStoryboard.Children.Add(myDoubleAnimation)
			Dim myBeginStoryboard As New BeginStoryboard()
			myBeginStoryboard.Storyboard = myStoryboard
			Dim myMouseEnterTrigger As New EventTrigger()
			myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
			myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
			rectangle02.Triggers.Add(myMouseEnterTrigger)

The previous sections described how to indirectly target a Freezable by starting with a FrameworkElement or FrameworkContentElement and creating a property chain to a Freezable sub-property. You can also use a Freezable as a starting point and indirectly target one of its Freezable sub-properties. One additional restriction applies when using a Freezable as a starting point for indirect targeting: the starting Freezable and every Freezable between it and the indirectly targeted sub-property must not be frozen.

To start a storyboard in Extensible Application Markup Language (XAML), you use a BeginStoryboard trigger action. BeginStoryboard distributes the animations to the objects and properties they animate, and starts the storyboard. (For details about this process, see the Animation and Timing System Overview.) If you give the BeginStoryboard a name by specifying its Name property, you make it a controllable storyboard. You can then interactively control the storyboard after it's started. The following is a list of controllable storyboard actions that you use with event triggers to control a storyboard.

In the following example, controllable storyboard actions are used to interactively control a storyboard.

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

The previous examples have shown how to animate using trigger actions. In code, you may also control a storyboard using interactive methods of the Storyboard class. For a Storyboard to be made interactive in code, you must use the appropriate overload of the storyboard's Begin method and specify true to make it controllable. See the Begin(FrameworkElement, Boolean) page for more information.

The following list shows the methods that can be used to manipulate a Storyboard after it has started:

The advantage to using these methods is that you don't need to create Trigger or TriggerAction objects; you just need a reference to the controllable Storyboard you want to manipulate.

Note: All interactive actions taken on a Clock, and therefore also on a Storyboard will occur on the next tick of the timing engine which will happen shortly before the next render. For example, if you use the Seek method to jump to another point in an animation, the property value does not change instantly, rather, the value changes on the next tick of the timing engine.

The following example shows how to apply and control animations using the interactive methods of the Storyboard class.


Imports Microsoft.VisualBasic
Imports System
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

You can use Storyboard objects to define animations in a Style. Animating with a Storyboard in a Style is similar to using a Storyboard elsewhere, with the following three exceptions:

  • You don't specify a TargetName; the Storyboard always targets the element to which the Style is applied. To target Freezable objects, you must use indirect targeting. For more information about indirect targeting, see the Indirect Targeting section.

  • You can't specify a SourceName for an EventTrigger or a Trigger.

  • You can't use dynamic resource references or data binding expressions to set Storyboard or animation property values. That's because everything inside a Style must be thread-safe, and the timing system must Freeze Storyboard objects to make them thread-safe. A Storyboard cannot be frozen if it or its child timelines contain dynamic resource references or data binding expressions. For more information about freezing and other Freezable features, see the Freezable Objects Overview.

  • In XAML, you can't declare event handlers for Storyboard or animation events.

For an example showing how to define a storyboard in a style, see the How to: Animate in a Style example.

You can use Storyboard objects to define animations in a ControlTemplate. Animating with a Storyboard in a ControlTemplate is similar to using a Storyboard elsewhere, with the following two exceptions:

For an example showing how to define a storyboard in a ControlTemplate, see the How to: Animate in a ControlTemplate example.

In styles and control templates, you can use Trigger objects to start a storyboard when a property changes. For examples, see How to: Trigger an Animation When a Property Value Changes and How to: Animate in a ControlTemplate.

Animations applied by property Trigger objects behave in a more complex fashion than EventTrigger animations or animations started using Storyboard methods. They "handoff" with animations defined by other Trigger objects, but compose with EventTrigger and method-triggered animations.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft