trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

Storyboardを切り替える(XAML)

目次

  1. WPFのCustomControlでアニメーション-概要
  2. LineにLinearGradientBrushを適用したものをCustomControlとして作る
  3. Storyboardを作成する(XAML)
  4. Storyboardを切り替える(XAML)←ここ
  5. Storyboardを切り替える(Code Behind)
  6. Storyboardを作成する(Code Behind)

目的

プロパティによって動作するStoryboardを切り替える

f:id:trsing:20210228223449g:plain

作成

.cs

  • 切り替えに必要な依存関係プロパティ(AnimationType、面倒なのでbool)を作成する

Generic.xaml

  • 必要なだけStoryboardを作成する(true時(gradientAnimationTrue),false時(gradientAnimationFalse)の二種類)
  • ControlTemplate.Triggerでプロパティと対応するStoryboardを設定する
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:GradientLineTest.Controls"
    >

    <Style TargetType="{x:Type local:GradientLineControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:GradientLineControl}">
                    <ControlTemplate.Resources>
                        <Storyboard x:Key="gradientAnimationTrue" RepeatBehavior="Forever" AutoReverse="True">
                                <DoubleAnimation Storyboard.TargetName="gradientLine"
                                 Storyboard.TargetProperty="(Line.Stroke).(LinearGradientBrush.GradientStops)[1].(GradientStop.Offset)"
                                 From="0" To="1"/>
                        </Storyboard>
                        <Storyboard x:Key="gradientAnimationFalse" RepeatBehavior="Forever" AutoReverse="True">
                            <DoubleAnimation Storyboard.TargetName="gradientLine"
                                 Storyboard.TargetProperty="(Line.Stroke).(LinearGradientBrush.GradientStops)[0].(GradientStop.Offset)"
                                 From="0" To="1"/>
                            <DoubleAnimation Storyboard.TargetName="gradientLine"
                                 Storyboard.TargetProperty="(Line.Stroke).(LinearGradientBrush.GradientStops)[1].(GradientStop.Offset)"
                                 From="0" To="1"/>
                        </Storyboard>
                    </ControlTemplate.Resources>
                    <ControlTemplate.Triggers>
                        <Trigger Property="AnimationType" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard x:Name="typeTrueAnimation" Storyboard="{StaticResource gradientAnimationTrue}"/>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <RemoveStoryboard BeginStoryboardName="typeTrueAnimation"/>
                            </Trigger.ExitActions>
                        </Trigger>
                        <Trigger Property="AnimationType" Value="False">
                            <Trigger.EnterActions>
                                <BeginStoryboard x:Name="typeFalseAnimation" Storyboard="{StaticResource gradientAnimationFalse}"/>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <RemoveStoryboard BeginStoryboardName="typeFalseAnimation"/>
                            </Trigger.ExitActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                    <Line x:Name="gradientLine"
                          X1="{TemplateBinding X1}" Y1="{TemplateBinding Y1}"
                          X2="{TemplateBinding X2}" Y2="{TemplateBinding Y2}"
                          StrokeThickness="10"
                          >
                        <Line.Stroke>
                            <LinearGradientBrush StartPoint="0.0,0.5" EndPoint="1.0,0.5">
                                <GradientStop Color="{Binding LeftColor,RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0"/>
                                <GradientStop Color="{Binding RightColor,RelativeSource={RelativeSource TemplatedParent}}" Offset="1"/>
                            </LinearGradientBrush>
                        </Line.Stroke>
                    </Line>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

注意点

Storyboardを書く場所について

Storyboardは<ControlTemplate.Triggers>から見える場所(<ControlTemplate.Resources><Style.Resources>)に書く。

<Line.Resources>に書くと<ControleTemplate.Triggers>から見えない(方法はあるのかもしれないけど知らない)。

Storyboard切り替え時の処理について

別のStoryboardを動かすなら元のStoryboardは止めないと混ざって期待通りの動作にならない。 (<Trigger.ExitActions> のとこに<RemoveStoryboard>を書いてプロパティが変わったら削除するようにしてる。止める場合は<StopStoryboard>だけどいろいろめんどそうだったので削除を使ってる)