StoryBoard(style)関連記事
やりたいこと
WPFアプリで簡単なアニメーションを実装したいときに<Storyboard>
をよく使うが、その書き方、特に動かし方(アニメーションのStartのさせ方)にいろいろあり、覚えられないので一旦まとめておきたい。
(Storyboardの**「Startのさせ方」**のみまとめる。Storyboard自体の使い方やできることは今回はやらない)
■ 書き方別/目的別 Storyboardの書き方
どういう書き方をしたいか、どういうときにStoryboardでアニメ―ションしたいかで、サンプルとなるコードをまとめた。
★Storyboardを書きたい場所
- 対象コントロールの中に直接書く
-
Resources
の中にまとめて書く
★目的別
- 単純な使い方(アプリ起動したらずっと動かしておきたい等)
- 対象Controlのイベント(MouseDown等)発生時に動かしたい(xamlのみ)
- ViewModel等のプロパティの変化時に動かしたい(xamlのみ)
- コードの中から動かしたい(xaml+cs)
■①対象コントロールの中に直接書く
<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の中にまとめて書く
<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
<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
<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
<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
<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>
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();
}
}
}
}