WPF でViewModel のプロパティが変更されたときにStoryboard を開始する方法で少し躓いたのでメモ。
開発環境は以下の通り。
ViewModel のプロパティの変更をトリガーにアニメーションするのが目的なので、まず思い浮かんだのがこれ↓
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnslocal="clr-namespace:BindingSoureChangedAnimation"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnsi="http://schemas.microsoft.com/expression/2010/interactivity"
xmlnsei="http://schemas.microsoft.com/expression/2010/interactions"
xClass="BindingSoureChangedAnimation.MainWindow"
Title="MainWindow"
Width="525"
Height="350"
dDataContext="{d:DesignInstance {x:Type local:MainWindowViewModel}, IsDesignTimeCreatable=True}"
mcIgnorable="d">
<WindowStyle>
<Style TargetType="{x:Type Window}">
<StyleTriggers>
<DataTrigger Binding="{Binding IsAnimation}"
Value="True">
<DataTriggerEnterActions>
<BeginStoryboard Storyboard="{DynamicResource ColorChangeStoryboard}"
xName="Begin_ColorChangeStoryboard" />
</DataTriggerEnterActions>
<DataTriggerExitActions>
<StopStoryboard BeginStoryboardName="Begin_ColorChangeStoryboard" />
</DataTriggerExitActions>
</DataTrigger>
</StyleTriggers>
</Style>
</WindowStyle>
<WindowResources>
<Storyboard xKey="ColorChangeStoryboard">
<ColorAnimationUsingKeyFrames StoryboardTargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
StoryboardTargetName="rectangle">
<EasingColorKeyFrame KeyTime="0"
Value="#FF7A7AFF" />
<EasingColorKeyFrame KeyTime="0:0:1"
Value="#FFFFFFA9" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</WindowResources>
<Grid>
<GridRowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</GridRowDefinitions>
<CheckBox Content="アニメーション"
IsChecked="{Binding IsAnimation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</CheckBox>
<Border GridRow="1">
<Rectangle xName="rectangle"
Fill="#FF7A7AFF"
Stroke="Black"
Margin="32" />
</Border>
</Grid>
</Window>
Window のStyle.Trigger のDataTrigger を使用するパターン。
これを実行するとこうなります。
Window のStyle からでは、Window.Resources 内のリソースにはアクセスできないとのこと…。
同様にWindow.Content のGrid のStyle でも実現はできません。
で、次の案。
Behavior のControlStoryboardAction を使用する。
ただ、このBehavior はEventTrigger になっているのでイベントの着火をトリガーとするため今回の目的には合致しません。(※)
いろいろ調べた結果、以下の方法で実現することができました。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnslocal="clr-namespace:BindingSoureChangedAnimation"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnsi="http://schemas.microsoft.com/expression/2010/interactivity"
xmlnsei="http://schemas.microsoft.com/expression/2010/interactions"
xClass="BindingSoureChangedAnimation.MainWindow"
Title="MainWindow"
Width="525"
Height="350"
dDataContext="{d:DesignInstance {x:Type local:MainWindowViewModel}, IsDesignTimeCreatable=True}"
mcIgnorable="d">
<WindowResources>
<Storyboard xKey="ColorChangeStoryboard"
RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames StoryboardTargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
StoryboardTargetName="rectangle">
<EasingColorKeyFrame KeyTime="0"
Value="#FF7A7AFF" />
<EasingColorKeyFrame KeyTime="0:0:1"
Value="#FFFFFFA9" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</WindowResources>
<iInteractionTriggers>
<eiDataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
Value="True">
<eiControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}" />
</eiDataTrigger>
<eiDataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
Value="True"
Comparison="NotEqual">
<eiControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}"
ControlStoryboardOption="Stop" />
</eiDataTrigger>
</iInteractionTriggers>
<WindowDataContext>
<localMainWindowViewModel />
</WindowDataContext>
<Grid>
<GridRowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</GridRowDefinitions>
<CheckBox Content="アニメーション"
IsChecked="{Binding IsAnimation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Border GridRow="1">
<Rectangle xName="rectangle"
Fill="#FF7A7AFF"
Stroke="Black"
Margin="32" />
</Border>
</Grid>
</Window>
変更点はここ
<iInteractionTriggers>
<eiDataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
Value="True">
<eiControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}" />
</eiDataTrigger>
<eiDataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
Value="True"
Comparison="NotEqual">
<eiControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}"
ControlStoryboardOption="Stop" />
</eiDataTrigger>
</iInteractionTriggers>
ControlStoryboardAction 使ってるんですが、そのトリガーに"ei:DataTrigger" を使用しています。
通常の"DataTrigger" とは違って"Microsoft.Expression.Interactivity.Core" 名前空間にいるやつです。
こいつを探し出すのが苦労したorz
通常、Blend からBehavior をドラッグ・アンド・ドロップで配置するとトリガーは、"EventTrigger" になります。
これを"ei:DataTrigger" に変更するには以下の手順を実行します。
1.Behavior を配置する。
2.EventTrigger をDataTrigger に変更する。
プロパティ ウィンドウの[トリガー] - [新規] をクリックします。
一覧から"DataTrigger" を選択して[OK] をクリックします。
3.トリガーの値を設定する。
プロパティ ウィンドウの[トリガー] "TriggerType" が"DataTrigger" に変わっていることを確認してViewModel のプロパティの値をバインドする。
これを探し出すのに一番時間がかかりました。
ちなみにControlStoryboardAction は、Play とStop それぞれのアクションを設定しないとStoryboard を開始、終了することができません。
また、値の比較種別として"Equal", "NotEqual" 以外にも"LessThan (未満)", "GreaterThan (~より大きい)" 等があるので、ViewModel のプロパティがある数値以上の場合にアニメーションを制御する といったこともできそうです。(未確認)
今回使用したソースはこちら↓↓↓
github.com