8.4 ストーリーボード
8.4.1 アニメーションを組み合わせる
これまでのサンプルでは、複数のアニメーションを個別に BeginAnimation() メソッドから実行させていましたが、この方法では関係しあうタイムラインを統合して管理することができません。複数のタイムラインを管理することができるストーリーボードと呼ばれる機能を使うことで、関連する個別のタイムラインを管理することができます。ストーリーボードには 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 クラスのコンストラクタは、パラメータを受け取りません。
public Storyboard ()
Storyboard クラスのスーパークラスである TimelineGroup クラスには、任意の数の子タイムラインを管理するための Children プロパティが用意されています。
public TimelineCollection Children { get; set; }
Children が返す TimelineCollection オブジェクトは、Timeline オブジェクトの配列を管理するためのコレクションです。このオブジェクトに、関連する一連のアニメーションの一部となるタイムラインを追加します。追加されたアニメーションは、Storyboard オブジェクトによって 1 つのタイムラインとして統合されます。
ストーリーボードに登録されているタイムラインを BeginAnimation() メソッドで個別に実装するようなことは行いません。そのため、Storyboard に設定されている子タイムラインの対象プロパティを設定する必要があります。タイムラインと変更対象のプロパティの関連付けは Storyboard クラスの静的な SetTargetProperty() メソッドを使います。
public static void SetTargetProperty ( DependencyObject element, PropertyPath path )
element には、対象となる依存プロパティに関連付ける Tileline オブジェクトを、path には対象となる依存プロパティを表す PropertyPath オブジェクトを指定します。
準備が整えば Storyboard クラスの Begin() メソッドで、子タイムラインを起動してアニメーションを開始することができます。すべてのタイムラインは同時に開始されるため、複数のタイムラインを組み合わせた複雑なアニメーションに適しています。
public void Begin (FrameworkElement containingObject)
containingObject には、ストーリーボードの対象となるプロパティを保有しているオブジェクトを指定します。
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は、黒い楕円形をクリックすると、一瞬だけだ円形が膨張するというアニメーションを実行します。このアニメーションは、Width プロパティに対するタイムラインと、Height プロパティに対するタイムラインを Storyboard に追加して、ストーリーボードとして実行しています。Begin() メソッドの呼び出しと同時に、すべてのタイムラインが実行されていることが確認できます。
8.4.2 ストーリーボードの制御
ストーリーボードが実行しているタイムライン全体を、ストーリーボードから一括して操作することができます。例えば、ストーリーボードとして実行されている複数のアニメーションを、同時に一時停止させたり、再開、停止などを行うことができます。
ストーリーボードのアニメーション再生を維持知的に停止させる場合は Pause() メソッドを呼び出します。
public void Pause (FrameworkElement containingObject)
Pause() メソッドをび出すと、ストーリーボードに含まれているすべてのアニメーションは、オブジェクトをタイムラインが変更途中だったプロパティを現在の値のままで停止します。アニメーションは Resume() メソッドから再開することができます。
public void Resume (FrameworkElement containingObject)
Resume() メソッドが実行されると、ストーリーボードを一時停止したプロパティの値からアニメーションが再開されます。ストーリーボードが一時停止されているかどうかは GetIsPaused() メソッドから取得できます。
public bool GetIsPaused (FrameworkElement containingObject)
ストーリーボートが Pause() メソッドによって一時停止されている場合は true が、そうでなければ false が返されます。
ストーリーボードの実行を強制的に停止させる場合は Stop() メソッドを呼び出します。
public void Stop ( FrameworkElement containingObject )
Stop() メソッドが呼び出されると、ストーリーボードで実行されていたすべてのタイムラインは、対象のプロパティを最終的な値に変更して終了します。
これらのメソッドを使えば、アニメーションの再生や一時停止、再開、終了、をプログラムで自由にコントロールすることができるようになります。例えば、ユーザーにアニメーションを操作させたい場合などに使うことができます。
ストーリーボードの実行を操作したい場合、ストーリーボードの開始時には次の Begin() メソッドを使ってください。Begin() メソッドはオーバーロードされています。
public void Begin ( FrameworkElement containingObject, bool isControllable )
containingObject しかパラメータを与えなかった場合は、ストーリーボードの操作は無効にされているため、Pause() や Stop() などを呼び出してもストーリーボードを停止させることはできません。ストーリーボードを操作したい場合は、isControllable パラメータに true を渡す必要があります。
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は、テキストのサイズを変更するアニメーションと、テキストの透明度を変更するアニメーションを同時に実行するストーリーボードを制御します。ウィンドウ上でマウスボタンをクリックすると、ストーリーボードが一時停止され、再度クリックすると再開されることを確認してください。