かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

WPF4.5入門 その58「Behavior」

WPFの標準部品ではないですが、Blend SDK for WPFに同梱されているBehaviorという部品があります。BlendはVisual Studioに同梱されているため、基本的に標準でついていると考えていいライブラリです。Behaviorは、TriggerとAction(WPFの同名の機能とは別物になります)と、Behaviorを提供しています。Triggerは、名前のとおり、何か処理のきっかけがあったことを示すための部品です。Actionは、Triggerに設定してTriggerの条件が満たされたタイミングで実行される処理になります。

TriggerとAction

Triggerは、WPF標準のTriggerと比較して独自のTriggerが作れるようになっているなど柔軟に作られています。代表的なTriggerを以下に示します。

  • EventTrigger : 指定したイベントが発生したときにActionを呼び出します。
  • TimerTrigger : 指定したタイミングでActionを呼び出します。
  • PropertyChangedEventTrigger : 指定したプロパティが変化したときにActionを呼び出します。

Triggerが特定の条件を満たしたときに呼び出されるActionの中で代表的なものを以下に示します。

  • CallMethodAction : 指定したメソッドを呼び出します。
  • ChangePropertyAction : プロパティの値を指定した値にしたり、インクリメントしたりすることができます。
  • ControlStoryboardAction : ストーリーボードを再生、停止などの操作をすることができます。
  • GoToStateAction : VisualStateを変更することができます。
  • InvokeCommandAction : 指定したCommandを呼び出します。
  • LaunchUriOrFileAction : 指定したUriかファイルを開きます。

TriggerとActionの使い方

TriggerとActionを使うには、Blend for Visual Studioで、使用したいActionを、対象のコントロールにドロップします。その後、プロパティウィンドウのTriggerType(デフォルトでEventTriggerが設定されています)の横の新規作成ボタンでTriggerの種類を指定します。 例として、5秒周期で指定したURLを開く処理をTriggerとActionで作成します。この例で使用するTriggerとActionは、以下のものになります。

  • TimerTrigger
  • LaunchUriOrFileAction

LaunchUriOrFileActionを、WindowのGrid上にドロップします。

そうすると、以下のようなXAMLが生成されます。デフォルトのTriggerとして、EventTriggerが指定されていることが確認できます。

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
    x:Class="BehaviorSample01.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonDown">
            <ei:LaunchUriOrFileAction/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Grid>
</Window>

オブジェクトとタイムラインから、LaunchUriOrFileActionを選択してPathプロパティにhttp://www.google.comなどのURLを入力します。次に、TriggerをTimerTriggerに変更します。Triggerの変更は、プロパティウィンドウのトリガーにあるTriggerTypeの新規作成を選択します。

f:id:okazuki:20141221205228p:plain

そうすると、Triggerを選択画面が表示されます。ここで、TimerTriggerを選択します。

f:id:okazuki:20141221205248p:plain

OKを選択するとTriggerがEventTriggerからTimerTriggerに変更されます。

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="BehaviorSample01.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <i:Interaction.Triggers>
            <ei:TimerTrigger>
                <ei:LaunchUriOrFileAction Path="http://www.google.com"/>
            </ei:TimerTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>

TimerTriggerは、MillisecondsPerTickプロパティでTriggerがActionを実行する間隔を指定できます。ここでは5000を設定します。この状態で実行すると、5秒間隔でGoogleのサイトが開かれます。

Behavior

TriggerとActionは、処理のきっかけと実際の処理が分離されていましたが、処理のきっかけと処理が分離されてないものがBehaviorとして提供されています。代表的なものとして以下のようなBehaviorが提供されています。

  • DataStateBehavior : BindingプロパティとValueプロパティの値が等しいときにTrueStateに遷移して等しくないときにFalseStateに遷移します。
  • FluidMoveBehavior : Panel内の要素の移動をアニメーションさせることができます。
  • MouseDragElementBehavior : タッチやマウス操作で、Behaviorを設定したコントロールを移動させることができるようになります。
  • TranslateZoomRotateBehavior : タッチやマウス操作で、Behaviorを設定したコントロールを回転、移動させることができるようになります。

例として、DataStateBehaviorを使用して、CheckBoxのチェックの有無でVisualStateを切り替えるXAMLを以下に示します。

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:System="clr-namespace:System;assembly=mscorlib" 
    x:Class="BehaviorSample02.MainWindow"
    Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="grid">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="TrueState">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames 
                            Storyboard.TargetProperty="(Panel.Background)" 
                            Storyboard.TargetName="grid">
                            <DiscreteObjectKeyFrame KeyTime="0">
                                <DiscreteObjectKeyFrame.Value>
                                    <SolidColorBrush Color="#FFFF8686"/>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="FalseState"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <i:Interaction.Behaviors>
            <ei:DataStateBehavior 
                TrueState="TrueState" 
                FalseState="FalseState" 
                Binding="{Binding IsChecked, ElementName=checkBox}" 
                Value="True"/>
        </i:Interaction.Behaviors>
        <CheckBox x:Name="checkBox" Content="CheckBox" />
    </Grid>
</Window>

TrueStateとFalseStateというVisualStateを定義して、DataStateBehaviorから参照しています。DataStateBehaviorのBindingをCheckBoxのIsCheckedと非もづけて、ValueプロパティにTrueを設定します。こうすることで、CheckBoxにチェックが入った時にTrueStateが、チェックが入っていないときにFalseStateに遷移するようになります。実行すると、CheckBoxにチェックをつけたときに背景が薄い赤色になります。

このように、Behaviorを使うと今までコードビハインドを使って書いていたような処理が部品化されているためBlend for Visual Studio上でドラッグアンドドロップしてプロパティを設定するだけで作成できるようになります。

過去記事