もくじ
→https://qiita.com/tera1707/items/4fda73d86eded283ec4f
Storyboard関連
- [WPF/xaml] xaml+C#で当番決めのためのルーレットを作る
- [WPF/xaml]Storyboardでアニメーションをつくる
- [WPF/xaml]Storyboardでアニメーションをつくる2(TargetPropertyの階層的な指定)
やりたいこと
こんな感じのスイッチを作って、押したら中の四角の部分が「ぐいーん」と左右に動いて、スイッチの入り切りを表現するようなものを作りたい。
⇔
サンプルコード
スイッチはCheckBox
を使い、そのStyleをうまいことやってやることで実現する。
<Window x:Class="WpfApp17.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:WpfApp17"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Background="Gray">
<Grid>
<!-- チェックボックス本体 -->
<CheckBox>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<!-- 見た目の設定 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- 外側の枠 -->
<Border Name="BackgroundBorder" CornerRadius="2" Height="28" Width="60" BorderBrush="White" BorderThickness="2"/>
<!-- 中のスイッチ部分 -->
<Rectangle x:Name="slider" Stroke="#FFFF0000" HorizontalAlignment="Left" Width="12" Height="18" StrokeThickness="0" RenderTransformOrigin="0.5,0.5" Margin="0" Fill="White">
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform X="5" Y="0" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
<!-- ストーリーボードの設定 -->
<ControlTemplate.Resources>
<Storyboard x:Key="OnChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="43" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUmChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="5" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<!-- トリガーの設定 -->
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<!-- IsCheckedがTrueになるときのStoryboard開始指示 -->
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" x:Name="OnChecking_BeginStoryboard" />
</Trigger.EnterActions>
<!-- IsCheckedがTrueから抜けるときのStoryboard開始指示 -->
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUmChecking}" x:Name="OnUnchecking_BeginStoryboard" />
</Trigger.ExitActions>
<!-- その他プロパティの変化定義(チェック時) -->
<Setter TargetName="slider" Property="Fill" Value="White" />
<Setter TargetName="BackgroundBorder" Property="Background" Value="Orange" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<!-- その他プロパティの変化定義(非チェック時) -->
<Setter TargetName="slider" Property="Fill" Value="White" />
<Setter TargetName="BackgroundBorder" Property="Background" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid>
</Window>
説明
大きく分けて、4つの部分がある。
部分 | 概要 |
---|---|
★チェックボックス本体 | ベースになるCheckBox を設置する |
★見た目の設定 | スイッチの見た目を、BorderやRectangleで作る |
★ストーリーボードの設定 | Storyboardを使って、どのコントロールのどのプロパティをどのように変化させる、ということを書く |
★トリガーの設定 | 何をトリガーにして、ストーリーボードを動作させるかを書く |
チェックボックス本体
ControlTemplate
を作って、それをチェックボックスのStyle
の中のTemplate
にセットする形でチェックボックスをカスタムする。
<CheckBox>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
・
・
見た目の設定
スイッチの見た目を、BorderやRectangleで作る。
<!-- ★見た目の設定 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- 外側の枠 -->
<Border Name="BackgroundBorder" CornerRadius="2" Height="28" Width="60" BorderBrush="White" BorderThickness="2"/>
<!-- 中のスイッチ部分 -->
<Rectangle x:Name="slider" Stroke="#FFFF0000" HorizontalAlignment="Left" Width="12" Height="18" StrokeThickness="0" Fill="White">
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform X="5" Y="0" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
ここで設置しているコントロールのプロパティを動かすことで、スイッチが左右に動くことを表現したいので、動かすものに名前を付けておく。(ここでは「BackgroundBorder」「slider」の2つの名前を付けている)
それぞれのコントロールのWidthやHeight(幅/高さ)、あとTranslateTransformのXやY(スイッチの上下の位置)は、適当な値(デザイナーを見ながら、ちょうどよさそうな値を手探りで見つけた感じ。)。
StoryBoardの方で、このslider
のTranslateTransformのXを変化させるということをする。
ストーリーボードの設定
Storyboard
の中に、Animationをセットして、どういう動きをさせるか定義する。
(19/06/06追記)下に、Storyboardについて追記しました。
<!-- ★ストーリーボードの設定 -->
<ControlTemplate.Resources>
<Storyboard x:Key="OnChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="43" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUmChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="5" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
Storyboardには名前を付けておく。後でTriggerのところで、この名前を使って呼び出す。
DoubleAnimationUsingKeyFramesについて
DoubleAnimationUsingKeyFramesのプロパティ | 概要 |
---|---|
BeginTime | アニメーションが開始するタイミング。これを00:00:05とすると、Checkboxを押してから5秒後にアニメ開始する。 |
Storyboard.TargetName | アニメーションさせたいコントロールの名前。 |
Storyboard.TargetProperty | アニメーションさせたいコントロールの、何のプロパティを変化させるか。 |
SplineDoubleKeyFrameについて
SplineDoubleKeyFrameのプロパティ | 概要 |
---|---|
Value | 変化させたプロパティの値。 |
KeyTime | 何秒間で、プロパティの値をValueで設定した値にもっていくか。00:00:00.2とすると、0.2秒でプロパティがValueの値まで変化する。 |
トリガーの設定
何をトリガーにして、ストーリーボードを動作させるかを書く。
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<!-- IsCheckedがTrueになるときのStoryboard開始指示 -->
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" x:Name="OnChecking_BeginStoryboard" />
</Trigger.EnterActions>
<!-- IsCheckedがTrueから抜けるときのStoryboard開始指示 -->
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUmChecking}" x:Name="OnUnchecking_BeginStoryboard" />
</Trigger.ExitActions>
<!-- その他プロパティの変化定義(チェック時) -->
<Setter TargetName="slider" Property="Fill" Value="White" />
<Setter TargetName="BackgroundBorder" Property="Background" Value="Orange" />
</Trigger>
・
・
</ControlTemplate.Triggers>
Triggerにセットするもの | 概要 |
---|---|
Trigger.EnterActions | Triggerで監視しているプロパティがValueの値になるときに行うStoryboardを指定する |
Trigger.ExitActions | Triggerで監視しているプロパティがValueの値から抜けるときに行うStoryboardを指定する |
BeginStoryboard |
Storyboard プロパティに、上で作ったStoryboardの名前を指定する |
備考
今回、DoubleAnimationUsingKeyFrames
を使って、TranslateTransform
のX
というdoubleの値を変化させることでアニメーションするということをしたが、ほかにも色を変化させるとか、いろいろできるっぽい。要調査。
補足 Storyboardの使い方(19/06/06追記)
Storyboardの使い方の基本は、下記のような使い方をする。
<!-- doubleの値を変化させるStoryboard -->
<Storyboard x:Key="OnChecking" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="RenderTransform.(TransformGroup.Children)[0].(TranslateTransform.X)">
<DiscreteDoubleKeyFrame KeyTime="00:00:02" Value="43" /> <!-- 値の変化がリニアではなく、指定した時間に、急に指定した値になる -->
<LinearDoubleKeyFrame KeyTime="00:00:04" Value="5" /> <!-- 値が現在値から目的値にリニアに変化していく -->
<EasingDoubleKeyFrame KeyTime="00:00:06" Value="43" /> <!-- イージングができる(イージング関数を指定しなければLinearと同じ) -->
<SplineDoubleKeyFrame KeyTime="00:00:08" Value="5" /> <!-- 変化の加速や減速ができる -->
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<!-- 色を変化させるStoryboard -->
<Storyboard x:Key="OnCheckingForColor" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="backColor" Storyboard.TargetProperty="Color">
<DiscreteColorKeyFrame KeyTime="00:00:02" Value="Red"/>
<LinearColorKeyFrame KeyTime="00:00:04" Value="Green"/>
<EasingColorKeyFrame KeyTime="00:00:06" Value="Blue"/>
<SplineColorKeyFrame KeyTime="00:00:08" Value="Yellow"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
■Storyboardクラス
ここに、トリガーからの呼び出しのための名前や、繰り返しの設定などを書く。
■xxxxxAnimationUsingKeyFramesクラス
AnimationTimeline
クラスを継承したものをここで使う。
AnimationTimeline
を継承するクラスはたくさんあり、ここで**「どんなプロパティを変化させるか」**が決まる。
例えばDoubleAnimationUsingKeyFrames
を使うなら、double型のプロパティを変化させる、となり、ColorAnimationUsingKeyFrames
を使うなら色を変化させる、となる。
■xxxxKeyFrameクラス
プロパティの種類(型)と、そのプロパティをどのように変化させるか、でここに使うクラスが決まる。
例えば、double型のプロパティを、初期値から徐々に目的の値まで変化させたい、となると、LinearDoubleKeyFrame
を使う。
Color型のプロパティを、指定した時間に、徐々にではなくいきなりその色に変えたい、となると、DiscreteColorKeyFrame
を使う。
xxxxKeyFrameクラスは、プロパティの種類ごとに、4つずつ派生クラスがあるっぽい。
例えば、double型用のクラスであれば下記の4つ。
- DiscreteDoubleKeyFrame
- LinearDoubleKeyFrame
- EasingDoubleKeyFrame
- SplineDoubleKeyFrame
見た限り、Color用についても同じものがあった。おそらく他の種類についても同じだと思われる。
参考
AnimationTimelineクラス
「DoubleAnimationUsingKeyFrames」などの元になっているクラス。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.animation.animationtimeline?view=netframework-4.8