ストーリーボードの概要

更新 : 2007 年 11 月

ここでは、Storyboard オブジェクトを使用してアニメーションを編成および適用する方法を示します。Storyboard オブジェクトを対話的に操作する方法について説明し、間接的なプロパティの対象化についての構文を示します。

必要条件

このトピックを理解するには、さまざまな種類のアニメーションとその基本的な機能に精通している必要があります。アニメーションの概要については、「アニメーションの概要」を参照してください。また、添付プロパティの使用方法についても理解しておく必要があります。添付プロパティの詳細については、「添付プロパティの概要」を参照してください。

ストーリーボードとは何か

タイムラインの型で役に立つのは、アニメーションだけではありません。他にも一連のタイムラインの編成を容易にし、タイムラインをプロパティに適用するための Timeline クラスが提供されています。コンテナ タイムラインは TimelineGroup クラスから派生し、ParallelTimelineStoryboard があります。

Storyboard はコンテナ タイムラインの型で、含まれる複数のタイムラインの対象情報を持っています。ストーリーボードには、その他のコンテナ タイムラインやアニメーションなど、任意の型の Timeline を格納できます。Storyboard オブジェクトを使用すると、さまざまなオブジェクトおよびプロパティに影響を与える複数のタイムラインを 1 つのタイムライン ツリーに結合でき、複雑なタイミング動作の編成および制御が容易になります。たとえば、次の 3 つのことを実行するボタンを必要としているとします。

  • ユーザーに選択されると、拡張して色が変わる。

  • クリックされると、縮小してから元のサイズに戻る。

  • 無効にされると、縮小し、50% の不透明度になる。

この場合、同じオブジェクトに適用するアニメーションのセットを複数用意し、ボタンの状態に応じてそれぞれ別の時間に再生します。Storyboard オブジェクトを使用すると、アニメーションを編成し、これらをグループ化して 1 つ以上のオブジェクトに適用できます。

ストーリーボードはどこで使用できるか

Storyboard を使用すると、アニメーション可能なクラスの依存関係プロパティをアニメーション化することができます (クラスをアニメーション可能にする方法の詳細については、「アニメーションの概要」を参照してください)。ただし、ストーリーボードはフレームワーク レベルの機能であるため、オブジェクトは FrameworkElementNameScope、または FrameworkContentElement に属している必要があります。

たとえば、Storyboard を使用すると、次の処理を実行できます。

ただし、名前が FrameworkElement または FrameworkContentElement を含めて登録されていなかったり、FrameworkElement または FrameworkContentElement のプロパティ設定で使用されなかった SolidColorBrush については、Storyboard を使用してアニメーション化することはできません。

ストーリーボードを使用してアニメーションを適用する方法

Storyboard を使用してアニメーションを編成および適用するには、Storyboard の子タイムラインとしてアニメーションを追加します。Storyboard クラスは、Storyboard.TargetName および Storyboard.TargetProperty の添付プロパティを提供します。これらのプロパティをアニメーションで設定して、アニメーションのターゲット オブジェクトとターゲット プロパティを指定します。

これらのターゲットにアニメーションを適用するには、トリガ アクションまたはメソッドを使用して Storyboard を開始します。XAML では、BeginStoryboard オブジェクトを EventTriggerTrigger、または DataTrigger で使用します。コード内で Begin メソッドを使用することもできます。

Storyboard の開始方法がサポートされているさまざまな場所、インスタンス単位、スタイル、コントロール テンプレート、データ テンプレートを次の表に示します。"インスタンス単位" とは、スタイル、コントロール テンプレート、またはデータ テンプレート内のインスタンスではなく、オブジェクトのインスタンスに直接アニメーションまたはストーリーボードを適用する方法のことです。

ストーリーボードが開始される場所

インスタンス単位

スタイル

コントロール テンプレート

データ テンプレート

BeginStoryboard およびEventTrigger

方法 : ストーリーボードを使ってプロパティをアニメーション化する

BeginStoryboard および Trigger プロパティ

×

方法 : プロパティ値が変化したときにアニメーションをトリガする

BeginStoryboard および DataTrigger

×

方法 : データが変化したときにアニメーションをトリガする

Begin メソッド

×

×

×

方法 : ストーリーボードを使ってプロパティをアニメーション化する

次の例では、Storyboard を使用して、Rectangle 要素の Width と、その Rectangle の描画に使用する SolidColorBrushColor をアニメーション化します。

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

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

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


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

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

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

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

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

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

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

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

以下のセクションでは、TargetName および TargetProperty の添付プロパティについて詳しく説明します。

フレームワーク要素、フレームワーク コンテンツ要素、およびフリーズ可能オブジェクトの対象化

アニメーションでは、そのターゲットを見つけるために、アニメーション化するターゲットの名前およびプロパティを認識する必要があることについては前のセクションで説明しました。アニメーション化するプロパティを指定することは簡単で、アニメーション化するプロパティの名前で Storyboard.TargetProperty を設定するだけです。アニメーション化するプロパティが含まれるオブジェクトの名前を指定するには、アニメーションで Storyboard.TargetName プロパティを設定します。

TargetName プロパティを機能させるには、ターゲット オブジェクトに名前が付いていなければなりません。XAML で FrameworkElement または FrameworkContentElement に名前を割り当てるのは、Freezable オブジェクトに名前を割り当てることとは異なります。

フレームワーク要素は、FrameworkElement クラスを継承するそれらのクラスです。フレームワーク要素の例としては、WindowDockPanelButtonRectangle などがあります。基本的に、ウィンドウ、パネル、およびコントロールはすべて要素です。フレームワーク コンテンツ要素は、FrameworkContentElement クラスを継承するそれらのクラスです。フレームワーク コンテンツ要素の例としては、FlowDocumentParagraph などがあります。型がフレームワーク要素またはフレームワーク コンテンツ要素であるかどうかが明確でない場合は、Name プロパティが含まれているかどうかを確認します。含まれている場合は、フレームワーク要素またはフレームワーク コンテンツ要素の可能性があります。確認するには、その型のページの「継承階層」をチェックしてください。

XAML でフレームワーク要素またはフレームワーク コンテンツ要素の対象化を有効にするには、その Name プロパティを設定します。また、コード内で RegisterName メソッドを使用して、各要素の名前を NameScope を作成した要素を含めて登録する必要があります。

次の例では、前の例からの続きとして、Rectangle に MyRectangle (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);

名前が割り当てられると、その要素のプロパティはアニメーション化できます。

<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 型は、Freezable クラスを継承するそれらのクラスです。Freezable の例としては、SolidColorBrushRotateTransformGradientStop などがあります。

XAML でアニメーションによる Freezable の対象化を有効にするには、x:Name 属性を使用して名前を割り当てます。コード内で RegisterName メソッドを使用して、NameScope を作成した要素を含めてその名前を登録する必要があります。

次の例では、Freezable オブジェクトに名前を割り当てます。

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

これで、オブジェクトをアニメーションのターゲットにすることができます。

<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 オブジェクトは、名前スコープを使用して TargetName プロパティを解決します。WPF 名前スコープの詳細については、「WPF 名前スコープ」を参照してください。TargetName プロパティが省略されている場合、アニメーションは、アニメーションが定義されている要素、スタイルの場合にはスタイルが設定されている要素をターゲットにします。

場合によっては、Freezable オブジェクトに名前を割り当てることができないことがあります。たとえば、Freezable がリソースとして宣言されたり、スタイル内でプロパティ値の設定に使用された場合は、名前を割り当てることができません。名前が割り当てられていないため、それを直接ターゲットにすることができません。ただし、間接的にターゲットにすることはできます。以下のセクションでは、間接的な対象化の使用方法について説明します。

間接的な対象化

Freezable がリソースとして宣言されたり、スタイル内でプロパティ値の設定に使用されたときなど、アニメーションで Freezable を直接ターゲットにできない場合があります。この場合、直接ターゲットにできなくても、Freezable オブジェクトをアニメーション化することができます。TargetName プロパティに Freezable の名前を設定するのではなく、Freezable が "属している" 要素の名前を指定します。たとえば、四角形要素の Fill の設定に使用された SolidColorBrush は、その四角形に属しています。ブラシをアニメーション化するには、設定に Freezable が使用されたフレームワーク要素またはフレームワーク コンテンツ要素のプロパティで開始され、アニメーション化する Freezable プロパティで終了するプロパティのチェーンを使用して、アニメーションの TargetProperty を設定します。

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

Freezable が固定されている場合は、複製が作成され、その複製がアニメーション化されることに注意してください。この場合、元のオブジェクトは実際にはアニメーション化されないため、元のオブジェクトの HasAnimatedProperties プロパティは引き続き false を返します。複製の詳細については、「Freezable オブジェクトの概要」を参照してください。

また、間接的なプロパティの対象化を使用した場合、存在しないオブジェクトはターゲットにできないことに注意してください。たとえば、実際にボタンの背景の設定に LinearGradientBrush を使用した場合、特定のボタンの BackgroundSolidColorBrush が設定されており、その色をアニメーション化しようとしたとします。この場合、例外はスローされませんが、LinearGradientBrushColor プロパティの変化に反応しないため、アニメーション効果を表示できません。

以下のセクションでは、間接的なプロパティの対象化についての構文について詳しく説明します。

XAML で Freezable のプロパティを間接的に対象化する

XAML でフリーズ可能オブジェクトのプロパティをターゲットにするには、次の構文を使用します。

ElementPropertyName.FreezablePropertyName

[場所]

  • ElementPropertyName は、Freezable を使用して設定される FrameworkElement のプロパティです。

  • FreezablePropertyName は、アニメーション化する Freezable のプロパティです。

次の項目の設定に使用された SolidColorBrushColor をアニメーション化する方法を次のコード例に示します。

四角形要素の Fill

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

コレクションまたはアレイに含まれるフリーズ可能オブジェクトをターゲットにしなければならない場合があります。

コレクションに含まれるフリーズ可能オブジェクトをターゲットにするには、次のパス構文を使用します。

ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

ここで、CollectionIndex はアレイまたはコレクションに含まれるオブジェクトのインデックスです。

たとえば、ある四角形の TransformGroup リソースが RenderTransform プロパティに適用されており、その変換の 1 つをアニメーション表示するとします。

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

次のコードは、前の例で示した RotateTransformAngle プロパティをアニメーション化する方法を示しています。

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

コード内で Freezable のプロパティを間接的に対象化する

コード内で PropertyPath オブジェクトを作成します。PropertyPath を作成する場合は、PathPathParameters を指定します。

PathParameters を作成するには、依存関係プロパティ識別子フィールドのリストが含まれる DependencyProperty 型の配列を作成します。最初の識別子フィールドは、Freezable を使用して設定された FrameworkElement または FrameworkContentElement のプロパティ用です。次の識別子フィールドは、ターゲットにする Freezable のプロパティを表します。これは、FreezableFrameworkElement オブジェクトに接続するプロパティのチェーンと考えてください。

四角形要素の Fill を設定するために使用された SolidColorBrushColor をターゲットにする依存関係プロパティのチェーンの例を次に示します。

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

Path も指定する必要があります。Path は、Path にその PathParameters の解釈方法を伝える String です。これには、次の構文を使います。

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

[場所]

  • OwnerPropertyArrayIndex は、Freezable を使用して設定された FrameworkElement オブジェクトのプロパティの識別子を格納する DependencyProperty 配列のインデックスです。

  • FreezablePropertyArrayIndex は、ターゲットにするプロパティの識別子を格納する DependencyProperty 配列のインデックスです。

前の例で定義した PathParameters を含む Path の例を次に示します。

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

次の例では、前の例のコードを組み合わせて、四角形要素の Fill を設定するために使用された SolidColorBrushColor をアニメーション化します。

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

コレクションまたはアレイに含まれるフリーズ可能オブジェクトをターゲットにしなければならない場合があります。たとえば、ある四角形の TransformGroup リソースが RenderTransform プロパティに適用されていて、その変換の 1 つをアニメーション表示しようとしているとします。

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

コレクションに含まれる Freezable をターゲットにするには、次のパス構文を使用します。

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

ここで、CollectionIndex はアレイまたはコレクションに含まれるオブジェクトのインデックスです。

RotateTransformAngle プロパティ (TransformGroup 内の 2 番目の変換) をターゲットにするには、次の Path および 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);

TransformGroup 内に含まれた RotateTransformAngle をアニメーション化するための完全なコード例を次に示します。

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

開始点として Freezable を使用して間接的に対象化する

前のセクションで、FrameworkElement または FrameworkContentElement で開始し、Freezable サブプロパティへのプロパティ チェーンを作成することによって、Freezable を間接的にターゲットにする方法について説明しました。また、開始点として Freezable を使用して、その Freezable サブプロパティの 1 つを間接的にターゲットにすることができます。間接的な対象化で開始点として Freezable を使用する場合、適用する制限が 1 つ追加されます。つまり、開始 Freezable と、間接的にターゲットにされたサブプロパティまでの各 Freezable は固定できません。

XAML での対話形式でのストーリーボードの制御

Extensible Application Markup Language (XAML) 内でストーリーボードを開始するには、BeginStoryboard トリガ アクションを使用します。BeginStoryboard は、アニメーション化するオブジェクトおよびプロパティにアニメーションを分配し、ストーリーボードを開始します (このプロセスの詳細については、「アニメーションとタイミング システムの概要」を参照してください)。BeginStoryboard は、Name プロパティを指定することによって名前を設定すると、制御可能なストーリーボードになります。ストーリーボードは、開始されると対話的に制御できます。ストーリーボードを制御するためにイベント トリガで使用する、制御可能なストーリーボード アクションの一覧を次に示します。

次の例では、制御可能なストーリーボード アクションを使用して、ストーリーボードを対話的に制御しています。

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

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

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

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

コードを使用した対話形式でのストーリーボードの制御

トリガ アクションを使用してアニメーション化する方法については、前の例で説明しました。コード内で Storyboard クラスの対話型メソッドを使用することにより、ストーリーボードを制御することもできます。コード内で Storyboard を対話型にするには、ストーリーボードの Begin メソッドの適切なオーバーロードを使用し、制御可能にするために true を指定する必要があります。詳細については、「Begin(FrameworkElement, Boolean)」を参照してください。

Storyboard の開始後の操作に使用できるメソッドの一覧を次に示します。

これらのメソッドを使用する利点は、Trigger オブジェクトまたは TriggerAction オブジェクトを作成する必要がなく、必要なのは操作対象の制御可能な Storyboard への参照だけであることです。

メモ : Clock で実行され、そのため Storyboard でも実行されるすべての対話形式のアクションは、次の描画の少し前に発生する、タイミング エンジンの次の目盛りで実行されます。たとえば、Seek メソッドを使用してアニメーション内の別のポイントにジャンプするとき、プロパティ値は直ちには変わらず、値はタイミング エンジンの次の目盛りで変わります。

Storyboard クラスの対話型メソッドを使用して、アニメーションを適用および制御する方法を次の例に示します。

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

        }         

    }

}

スタイル内でアニメーション化を行う

Storyboard オブジェクトを使用すると、Style 内でアニメーションを定義できます。Style 内の Storyboard によってアニメーション化することは、他の場所の Storyboard を使用することと同じですが、次の 3 点が異なります。

  • TargetName を指定しない場合、Storyboard は、常に Style が適用される要素をターゲットにします。Freezable オブジェクトをターゲットにするには、間接的な対象化を使用する必要があります。間接的な対象化の詳細については、「間接的な対象化」を参照してください。

  • EventTrigger または TriggerSourceName は指定できません。

  • Storyboard またはアニメーションのプロパティ値を設定する際に、動的リソース参照またはデータ バインディング式は使用できません。これは、Style 内のものはすべてスレッド セーフである必要があり、タイミング システムはこれらをスレッド セーフにする Freeze Storyboard オブジェクトである必要があるからです。Storyboard は、それ自身またはその子タイムラインに動的リソース参照またはデータ バインディング式が含まれている場合、固定できません。フリーズおよびその他の Freezable 機能の詳細については、「Freezable オブジェクトの概要」を参照してください。

  • XAML では、Storyboard またはアニメーション イベントのイベント ハンドラを宣言できません。

スタイル内でストーリーボードを定義する方法の例については、「方法 : スタイル内でアニメーション化を行う」の例を参照してください。

ControlTemplate 内でアニメーション化を行う

Storyboard オブジェクトを使用すると、ControlTemplate 内でアニメーションを定義できます。ControlTemplate 内の Storyboard によってアニメーション化することは、他の場所の Storyboard を使用することと同じですが、次の 2 点が異なります。

  • TargetName が参照できるのは、ControlTemplate の子オブジェクトだけです。TargetName が指定されていない場合、アニメーションは ControlTemplate が適用される要素をターゲットにします。

  • EventTrigger または TriggerSourceName が参照できるのは、ControlTemplate の子オブジェクトだけです。

  • Storyboard またはアニメーションのプロパティ値を設定する際に、動的リソース参照またはデータ バインディング式は使用できません。これは、ControlTemplate 内のものはすべてスレッド セーフである必要があり、タイミング システムはこれらをスレッド セーフにする Freeze Storyboard オブジェクトである必要があるからです。Storyboard は、それ自身またはその子タイムラインに動的リソース参照またはデータ バインディング式が含まれている場合、固定できません。フリーズおよびその他の Freezable 機能の詳細については、「Freezable オブジェクトの概要」を参照してください。

  • XAML では、Storyboard またはアニメーション イベントのイベント ハンドラを宣言できません。

ControlTemplate でストーリーボードを定義する方法の例については、「ControlTemplate 内でアニメーション化を行う」の例を参照してください。

プロパティ値が変化したときにアニメーション化を行う

スタイル内およびコントロール テンプレート内では、トリガ オブジェクトを使用して、プロパティが変化したときにストーリーボードを開始します。使用例については、「方法 : プロパティ値が変化したときにアニメーションをトリガする」および「ControlTemplate 内でアニメーション化を行う」を参照してください。

プロパティの Trigger オブジェクトによって適用されるアニメーションの動作は、EventTrigger アニメーション、または Storyboard メソッドを使用して開始されるアニメーションより複雑です。他の Trigger オブジェクトによって定義されるアニメーションで "ハンドオフ" しますが、EventTrigger およびメソッドでトリガされるアニメーションで構成されます。

参照

概念

アニメーションの概要

プロパティ アニメーションの手法の概要

Freezable オブジェクトの概要