LoginSignup
8
7

More than 1 year has passed since last update.

[C#/WPF] Storyboardの動かし方(Startのさせ方) あれこれ

Last updated at Posted at 2020-10-31

StoryBoard(style)関連記事

やりたいこと

WPFアプリで簡単なアニメーションを実装したいときに<Storyboard>をよく使うが、その書き方、特に動かし方(アニメーションのStartのさせ方)にいろいろあり、覚えられないので一旦まとめておきたい。
(Storyboardの「Startのさせ方」のみまとめる。Storyboard自体の使い方やできることは今回はやらない)

■ 書き方別/目的別 Storyboardの書き方

どういう書き方をしたいか、どういうときにStoryboardでアニメ―ションしたいかで、サンプルとなるコードをまとめた。

★Storyboardを書きたい場所

★目的別

■①対象コントロールの中に直接書く

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300">
    <Rectangle x:Name="MyRect" Stroke="Red" StrokeThickness="5" Width="100" Height="100" RenderTransformOrigin="0.5 0.5">
        <Rectangle.RenderTransform>
            <TransformGroup>
                <RotateTransform Angle="0"/>
            </TransformGroup>
        </Rectangle.RenderTransform>

        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever" Timeline.DesiredFrameRate="30">
                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="MyRect" 
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                            <LinearDoubleKeyFrame KeyTime="00:00:01.5" Value="360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
</Window>

■②Resourcesの中にまとめて書く

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300">
    <Window.Resources>
        <Storyboard x:Key="MyRoundingAnimation" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <Rectangle x:Name="MyRect" Stroke="Red" StrokeThickness="5" Width="100" Height="100" RenderTransformOrigin="0.5 0.5">
        <Rectangle.RenderTransform>
            <TransformGroup>
                <RotateTransform Angle="0"/>
            </TransformGroup>
        </Rectangle.RenderTransform>

        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Loaded">
                <BeginStoryboard Storyboard="{StaticResource MyRoundingAnimation}" />
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
</Window>

■③styleの中に書く/コントロールのプロパティ(IsMouseOver等)の変化でStart

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300"
        Name="root">
    <Window.Resources>
        <Storyboard x:Key="MyRoundingAnimation" RepeatBehavior="1">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <Grid>
        <Rectangle Stroke="Red" StrokeThickness="3" RenderTransformOrigin="0.5 0.5" Fill="Aqua" Margin="50">
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" />
                </TransformGroup>
            </Rectangle.RenderTransform>

            <Rectangle.Style>
                <Style TargetType="Rectangle">
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource MyRoundingAnimation}" Name="bsb"/>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <StopStoryboard BeginStoryboardName="bsb"/>
                            </Trigger.ExitActions>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Grid>
</Window>


<Style.Triggers>の中で、<Trigger Property="IsMouseOver" Value="True">を書くことはできたが、
<RectAngle.Triggers>の中に<Trigger Property="IsMouseOver" Value="True">を書くことはできなかった。
(Triggersの中はEventTriggerでないといけない、と怒られる)

■④ViewModel等のプロパティの変化でStart

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300"
        Name="root">
    <Window.Resources>
        <Storyboard x:Key="MyRoundingAnimation" RepeatBehavior="1">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <Grid>
        <!-- このチェックボックスがプロパティをONOFFする -->
        <CheckBox IsChecked="{Binding Chk, ElementName=root}"/>
        <Rectangle Stroke="Red" StrokeThickness="3" RenderTransformOrigin="0.5 0.5" Margin="50" >
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" />
                </TransformGroup>
            </Rectangle.RenderTransform>

            <Rectangle.Style>
                <Style TargetType="Rectangle">
                    <Style.Triggers>
                        <!-- プロパティのONOFFでStoryBoardを動かしたり止めたりする -->
                        <DataTrigger Binding="{Binding Chk, ElementName=root}" Value="True">
                            <DataTrigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource MyRoundingAnimation}" Name="bsb"/>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <StopStoryboard BeginStoryboardName="bsb"/>
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Grid>
</Window>

■⑤ViewModel等のプロパティの変化でStart(別解)

Blend SDK for WPFに同梱されているBehaviorというのを使う。
参考:https://blog.okazuki.jp/category/XAML?page=1419259848

下記で行った準備が必要。(参照の追加)
https://qiita.com/tera1707/items/7ecde6e97a19437cbf72#eventtrigger%E3%82%92%E4%BD%BF%E3%81%86

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:AnimationTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300"
        Name="root">
    <Window.Resources>
        <Storyboard x:Key="MyRoundingAnimation" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="MyRect"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <!-- プロパティのONOFFでStoryboardを制御 -->
    <i:Interaction.Triggers>
        <ei:DataTrigger Binding="{Binding Chk, ElementName=root}" Value="true">
            <ei:DataTrigger.Actions>
                <ei:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{StaticResource MyRoundingAnimation}" />
            </ei:DataTrigger.Actions>
        </ei:DataTrigger>
        <ei:DataTrigger Binding="{Binding Chk, ElementName=root}" Value="false">
            <ei:DataTrigger.Actions>
                <ei:ControlStoryboardAction ControlStoryboardOption="Stop" Storyboard="{StaticResource MyRoundingAnimation}" />
            </ei:DataTrigger.Actions>
        </ei:DataTrigger>
    </i:Interaction.Triggers>

    <Grid>
        <!-- このチェックボックスがプロパティをONOFFする -->
        <CheckBox IsChecked="{Binding Chk, ElementName=root}"/>

        <Rectangle x:Name="MyRect" Stroke="Red" StrokeThickness="3" RenderTransformOrigin="0.5 0.5" Margin="50" >
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" />
                </TransformGroup>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Grid>
</Window>

■⑥c#コードの中からStart

MainWindow.xaml
<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300"
        Name="root">
    <Window.Resources>
        <Storyboard x:Key="MyRoundingAnimation" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="MyRect"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)">
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <Grid>
        <ToggleButton Content="ボタン" HorizontalAlignment="Left" VerticalAlignment="Top" Click="ToggleButton_Click"/>
        <Rectangle x:Name="MyRect" Stroke="Red" StrokeThickness="3" RenderTransformOrigin="0.5 0.5" Margin="50" >
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" />
                </TransformGroup>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;

namespace AnimationTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void ToggleButton_Click(object sender, RoutedEventArgs e)
        {
            // StoryBoardを検索
            var sb = FindResource("MyRoundingAnimation") as Storyboard;

            // トグルボタンを押すたびにstart/stopする
            if (sender is ToggleButton tb)
            {
                if (tb.IsChecked.Value) sb.Begin();
                else                    sb.Stop();
            }
        }
    }
}
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7