ストーリーボードの概要

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

必須コンポーネント

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

ストーリーボードとは

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

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

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

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

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

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

ストーリーボードが使える場所

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

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

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

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

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

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

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

ストーリーボードが開始される場所 インスタンス単位 スタイル コントロール テンプレート データ テンプレート
BeginStoryboard および EventTrigger はい はい はい はい ストーリーボードを使ってプロパティをアニメーション化する
BeginStoryboard およびプロパティ Trigger いいえ はい はい はい プロパティ値が変化したときにアニメーションをトリガーする
BeginStoryboard およびプロパティ MultiTrigger いいえ はい はい はい MultiTrigger クラスの例
BeginStoryboard および DataTrigger いいえ はい はい はい 方法: データが変化したときにアニメーションをトリガーする
BeginStoryboard および MultiDataTrigger いいえ はい はい はい MultiDataTrigger クラスの例
Begin メソッド はい いいえ いいえ いいえ ストーリーボードを使ってプロパティをアニメーション化する

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

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

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

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

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

注意事項

TargetName の代わりに Target プロパティを使用して、オブジェクトに直接バインドすることはできますが、シリアル化することはできません。 Target オブジェクトが XAML で正しく参照できるという保証はありません。

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

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

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

次の例 (前の例からの抜粋) では、Rectangle (FrameworkElement 型) に MyRectangle という名前を割り当てています。

<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 XAML 名前スコープ」を参照してください。 TargetName プロパティが省略されている場合、アニメーションのターゲットは、アニメーションが定義されている要素、またはスタイルの場合にはスタイルが設定されている要素になります。

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

間接的な対象化

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

<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 オブジェクトの概要」をご覧ください。

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

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

XAML でフリーズ可能オブジェクトのプロパティを間接的に対象化する

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

プロパティの構文
ElementPropertyName.FreezablePropertyName

Where

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

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

次のコードでは、四角形要素の Fill の設定に使用された SolidColorBrushColor をアニメーション化する方法を示します。

<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 は配列またはコレクションに含まれるオブジェクトのインデックスです。

たとえば、ある四角形の RenderTransform プロパティに TransformGroup リソースが適用されていて、それに含まれている変換の 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>  

コードでフリーズ可能オブジェクトのプロパティを間接的に対象化する

コードで、PropertyPath オブジェクトを作成します。 PropertyPath を作成するときに、PathPathParameters を指定します。

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

次の例に示す依存関係プロパティのチェーンでは、四角形要素の Fill の設定に使用された SolidColorBrushColor がターゲットになります。

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

Path も指定する必要があります。 Path は、PathPathParameters の解釈方法を伝える String です。 次の構文が使用されます。

プロパティ パスの構文
(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Where

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

コレクションまたは配列に含まれるフリーズ可能オブジェクトをターゲットにしなければならない場合があります。 たとえば、ある四角形の RenderTransform プロパティに TransformGroup リソースが適用されていて、それに含まれている変換の 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 は、アニメーション化するオブジェクトおよびプロパティにアニメーションを配布し、ストーリーボードを開始します (このプロセスの詳細については「アニメーションとタイミング システムの概要」をご覧ください)。Name プロパティを指定して BeginStoryboard に名前を付けると、制御可能なストーリーボードになります。 ストーリーボードが開始すると対話的に制御できます。 制御可能なストーリーボード アクションの一覧を次に示します。これらをイベント トリガーで使用して、ストーリーボードを制御します。

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

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

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

トリガー アクションを使用してアニメーション化する方法については、前の例で説明しました。 コードでも、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);
        }
    }
}

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

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

Storyboard オブジェクトを使用して Style 内でアニメーションを定義できます。 Style での Storyboard を使用したアニメーション化は、Storyboard を他の場所で使用する場合と似ていますが、次の 3 点が異なります。

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

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

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

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

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

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

Storyboard オブジェクトを使用して ControlTemplate 内でアニメーションを定義できます。 ControlTemplate での Storyboard を使用したアニメーション化は、Storyboard を他の場所で使用する場合と似ていますが、次の 2 点が異なります。

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

  • EventTrigger または TriggerSourceName は、ControlTemplate の子オブジェクトしか参照できません。

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

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

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

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

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

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

関連項目