WisdomSoft - for your serial experiences.

8.4 ストーリーボード

複数のタイムラインを組み合わせ、複数のアニメーションを複雑に組み合わせるにはストーリーボードを利用します。

8.4.1 アニメーションを組み合わせる

これまでのサンプルでは、複数のアニメーションを個別に BeginAnimation() メソッドから実行させていましたが、この方法では関係しあうタイムラインを統合して管理することができません。複数のタイムラインを管理することができるストーリーボードと呼ばれる機能を使うことで、関連する個別のタイムラインを管理することができます。ストーリーボードには System.Windows.Media.Animation.Storyboard クラスを使います。

System.Windows.Media.Animation.Storyboard クラス
System.Object 
   System.Windows.Threading.DispatcherObject 
     System.Windows.DependencyObject 
       System.Windows.Freezable 
         System.Windows.Media.Animation.Animatable 
           System.Windows.Media.Animation.Timeline 
             System.Windows.Media.Animation.TimelineGroup 
               System.Windows.Media.Animation.ParallelTimeline 
                System.Windows.Media.Animation.Storyboard
public class Storyboard : ParallelTimeline

このクラスは、任意の数のタイムラインを子タイムラインとして保有することができる TimelineGroup クラスから派生しています。Storyboard クラスを利用することで、個別のタイムラインを相対的に関連付けさせ、全体的なアニメーションの流れの部品として統合することができます。

Storyboard クラスのコンストラクタは、パラメータを受け取りません。

Storyboard クラスのコンストラクタ
public Storyboard ()

Storyboard クラスのスーパークラスである TimelineGroup クラスには、任意の数の子タイムラインを管理するための Children プロパティが用意されています。

TimelineGroup クラス Children プロパティ
public TimelineCollection Children { get; set; }

Children が返す TimelineCollection オブジェクトは、Timeline オブジェクトの配列を管理するためのコレクションです。このオブジェクトに、関連する一連のアニメーションの一部となるタイムラインを追加します。追加されたアニメーションは、Storyboard オブジェクトによって 1 つのタイムラインとして統合されます。

ストーリーボードに登録されているタイムラインを BeginAnimation() メソッドで個別に実装するようなことは行いません。そのため、Storyboard に設定されている子タイムラインの対象プロパティを設定する必要があります。タイムラインと変更対象のプロパティの関連付けは Storyboard クラスの静的な SetTargetProperty() メソッドを使います。

Storyboard クラス SetTargetProperty() メソッド
public static void SetTargetProperty (
	DependencyObject element, PropertyPath path
)

element には、対象となる依存プロパティに関連付ける Tileline オブジェクトを、path には対象となる依存プロパティを表す PropertyPath オブジェクトを指定します。

準備が整えば Storyboard クラスの Begin() メソッドで、子タイムラインを起動してアニメーションを開始することができます。すべてのタイムラインは同時に開始されるため、複数のタイムラインを組み合わせた複雑なアニメーションに適しています。 

Storyboard クラス Begin() メソッド
public void Begin (FrameworkElement containingObject)

containingObject には、ストーリーボードの対象となるプロパティを保有しているオブジェクトを指定します。

コード1
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

class Test : Window {
	[STAThread]
	public static void Main() {
		Window wnd = new Test();
		Application app = new Application();
		app.Run(wnd);
	}

	private Ellipse ellipse;
	private Storyboard story;
	public Test() {
		ellipse = new Ellipse();
		ellipse.Fill = Brushes.Black;
		ellipse.Width = 200;
		ellipse.Height = 200;
		ellipse.MouseUp += ellipseMouseUp;

		Duration duration = new Duration(TimeSpan.FromMilliseconds(100));

		DoubleAnimation anime1 = new DoubleAnimation(ellipse.Width, ellipse.Width + 50, duration);
		anime1.AutoReverse = true;
		Storyboard.SetTargetProperty(anime1, new PropertyPath(Ellipse.WidthProperty));

		DoubleAnimation anime2 = new DoubleAnimation(ellipse.Height, ellipse.Height + 50, duration);
		anime2.AutoReverse = true;
		Storyboard.SetTargetProperty(anime2, new PropertyPath(Ellipse.HeightProperty));

		story = new Storyboard();
		story.Children.Add(anime1);
		story.Children.Add(anime2);

		Content = ellipse;
	}

	private void ellipseMouseUp(object sender, MouseEventArgs e) {
		story.Begin(ellipse);
	}
}
実行結果
コード1 実行結果

コード1は、黒い楕円形をクリックすると、一瞬だけだ円形が膨張するというアニメーションを実行します。このアニメーションは、Width プロパティに対するタイムラインと、Height プロパティに対するタイムラインを Storyboard に追加して、ストーリーボードとして実行しています。Begin() メソッドの呼び出しと同時に、すべてのタイムラインが実行されていることが確認できます。

8.4.2 ストーリーボードの制御

ストーリーボードが実行しているタイムライン全体を、ストーリーボードから一括して操作することができます。例えば、ストーリーボードとして実行されている複数のアニメーションを、同時に一時停止させたり、再開、停止などを行うことができます。

ストーリーボードのアニメーション再生を維持知的に停止させる場合は Pause() メソッドを呼び出します。

Storyboard クラス Pause() メソッド
public void Pause (FrameworkElement containingObject)

Pause() メソッドをび出すと、ストーリーボードに含まれているすべてのアニメーションは、オブジェクトをタイムラインが変更途中だったプロパティを現在の値のままで停止します。アニメーションは Resume() メソッドから再開することができます。

Storyboard クラス Resume() メソッド
public void Resume (FrameworkElement containingObject)

Resume() メソッドが実行されると、ストーリーボードを一時停止したプロパティの値からアニメーションが再開されます。ストーリーボードが一時停止されているかどうかは GetIsPaused() メソッドから取得できます。

Storyboard クラス GetIsPaused() メソッド
public bool GetIsPaused (FrameworkElement containingObject)

ストーリーボートが Pause() メソッドによって一時停止されている場合は true が、そうでなければ false が返されます。

ストーリーボードの実行を強制的に停止させる場合は Stop() メソッドを呼び出します。

Storyboard クラス Stop() メソッド
public void Stop (
	FrameworkElement containingObject
)

Stop() メソッドが呼び出されると、ストーリーボードで実行されていたすべてのタイムラインは、対象のプロパティを最終的な値に変更して終了します。

これらのメソッドを使えば、アニメーションの再生や一時停止、再開、終了、をプログラムで自由にコントロールすることができるようになります。例えば、ユーザーにアニメーションを操作させたい場合などに使うことができます。

ストーリーボードの実行を操作したい場合、ストーリーボードの開始時には次の Begin() メソッドを使ってください。Begin() メソッドはオーバーロードされています。

Storyboard クラス Begin() メソッド
public void Begin (
	FrameworkElement containingObject,
	bool isControllable
)

containingObject しかパラメータを与えなかった場合は、ストーリーボードの操作は無効にされているため、Pause() や Stop() などを呼び出してもストーリーボードを停止させることはできません。ストーリーボードを操作したい場合は、isControllable パラメータに true を渡す必要があります。

コード2
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Controls;

class Test : Window {
	[STAThread]
	public static void Main() {
		Window wnd = new Test();
		Application app = new Application();
		app.Run(wnd);
	}

	private TextBlock textBlock;
	private Storyboard story;

	public Test() {
		textBlock = new TextBlock();
		textBlock.Text = "Kitty on your lap";

		Duration duration1 = new Duration(TimeSpan.FromMilliseconds(5000));
		Duration duration2 = new Duration(TimeSpan.FromMilliseconds(1000));

		DoubleAnimation anime1 = new DoubleAnimation(10, 60 , duration1);
		anime1.AutoReverse = true;
		anime1.RepeatBehavior = RepeatBehavior.Forever;
		Storyboard.SetTargetProperty(anime1, new PropertyPath(TextBlock.FontSizeProperty));

		DoubleAnimation anime2 = new DoubleAnimation(1, 0 , duration2);
		anime2.AutoReverse = true;
		anime2.RepeatBehavior = RepeatBehavior.Forever;
		Storyboard.SetTargetProperty(anime2, new PropertyPath(UIElement.OpacityProperty));

		story = new Storyboard();
		story.Children.Add(anime1);
		story.Children.Add(anime2);

		story.Begin(textBlock, true);
		Content = textBlock;

		MouseUp += mouseUp;
	}

	private void mouseUp(object sender, MouseButtonEventArgs e) {
		if (story.GetIsPaused(textBlock)) story.Resume(textBlock);
		else story.Pause(textBlock);
	}
}
実行結果
コード2 実行結果

コード2は、テキストのサイズを変更するアニメーションと、テキストの透明度を変更するアニメーションを同時に実行するストーリーボードを制御します。ウィンドウ上でマウスボタンをクリックすると、ストーリーボードが一時停止され、再度クリックすると再開されることを確認してください。