かずきのBlog@hatena

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

WPF4.5入門 その59「Behaviorの自作」

BehaviorやTriggerとActionを使用することで、簡単なロジックがRAD環境で構築できることがわかりました。ここでは、ありもののBehaviorを使うのではなく自作のBehaviorやTrigger/Actionを作成する方法について示します。Behaviorは、コードビハインドに何回も同じ処理を書いていた場合、作成するとよいことが多いです。では作成したみたいと思います。

Behaviorの自作

ここで作成するのは、ボタンをクリックするとHello worldと表示するBehaviorを自作したいと思います。 Behaviorを作成するために以下のアセンブリを参照に追加します。(Behaviorを使うときにはBlendが自動で追加していたものになります)

  • System.Windows.Interactivity
  • Microsoft.Expression.Interactions

バージョンは4.5のものを追加してください。

Behaviorの作成には、Behaviorクラスを継承します。Behaviorクラスの型引数には、Behaviorを置くことができる型を指定します。特に指定がなければDependencyObjectなどを指定すればよいです。今回はButtonに置くので、Buttonを指定します。またTypeConstraint属性でもBehaviorを置ける型を指定します。

using System;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace BehaviorSample03
{
    [TypeConstraint(typeof(Button))]
    public class AlertBehavior : Behavior<Button>
    {
    }
}

Behaviorは、対象に設定されたときに呼び出されるOnAttachedメソッドと、対象から外されるときに呼び出されるOnDetachingメソッドをオーバーライドして処理を作成していきます。今回は、OnAttachedメソッドでクリックイベントを購読して、OnDetachingメソッドでクリックイベントの購読を解除します。クリックイベントのイベントハンドラでは、MessageBoxを表示しています。

[TypeConstraint(typeof(Button))]
public class AlertBehavior : Behavior<Button>
{
    protected override void OnAttached()
    {
        // AssociatedObjectのイベントを購読する
        this.AssociatedObject.Click += this.ButtonClicked;
    }

    protected override void OnDetaching()
    {
        // イベントの購読解除
        this.AssociatedObject.Click += this.ButtonClicked;
    }

    // イベントで処理をする
    private void ButtonClicked(object sender, System.Windows.RoutedEventArgs e)
    {
        MessageBox.Show("Hello world");
    }

}

ビルドすると、BlendでAlertBehaviorが使えるようになります。Buttonを画面に置いて、その上にAlertBehaviorをドロップします。

f:id:okazuki:20141222232401p:plain

XAMLを以下に示します。

<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:local="clr-namespace:BehaviorSample03" 
    x:Class="BehaviorSample03.MainWindow"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" 
Margin="10,10,0,0" VerticalAlignment="Top" Width="75">
            <i:Interaction.Behaviors>
                <local:AlertBehavior/>
            </i:Interaction.Behaviors>
        </Button>
    </Grid>
</Window>

実行してボタンをクリックすると、MessageBoxが表示されます。

f:id:okazuki:20141222232453p:plain

TriggerとActionの自作

Triggerを作成するには、System.Windows.Interactivity名前空間のTriggerBaseクラスを継承します。Behaviorと同様にOnAttachedメソッドとOnDetachingメソッドがあるので、そこでイベントを購読するなどのTriggerがActionを実行するためのセットアップをします。TriggerBaseクラスのInvokeActionsメソッドを呼び出すことで、Triggerに設定されたActionを呼び出すことができます。その際に、引数を渡すことでActionに、情報を渡すこともできます。 ここでは、先ほどのAlertBehaviorを、TriggerとActionに分解してみようと思います。Triggerのコードを以下に示します。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace BehaviorSample04
{
    [TypeConstraint(typeof(Button))]
    public class ButtonClickTrigger : TriggerBase<Button>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.Click += this.ButtonClick;
        }

        private void ButtonClick(object sender, RoutedEventArgs e)
        {
            this.InvokeActions(e);
        }

        protected override void OnDetaching()
        {
            this.AssociatedObject.Click -= this.ButtonClick;
        }
    }
}

Actionは、TriggerActionクラスを継承して、Invokeメソッドをオーバーライドしてそこに処理を記述します。今回のサンプルでは、MessageBoxを表示しています。Behaviorと同様にTypeConstraint属性でActionを置ける型の指定や、DefaultTrigger属性で、デフォルトで設定するTriggerの型を指定できます。(指定しない場合はEventTriggerが使われます)今回の例では、Buttonに置いたときにButtonClickTriggerクラスを使用するように設定しています。コードを以下に示します。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace BehaviorSample04
{
    [TypeConstraint(typeof(Button))]
    [DefaultTrigger(typeof(Button), typeof(ButtonClickTrigger))]
    public class AlertAction : TriggerAction<Button>
    {
        protected override void Invoke(object parameter)
        {
            MessageBox.Show("Hello world");
        }
    }
}

画面にButtonを置いてAlertActionをドロップすると、以下のようなXAMLが生成されます。

<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:local="clr-namespace:BehaviorSample04" 
    x:Class="BehaviorSample04.MainWindow"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" 
                Margin="10,10,0,0" VerticalAlignment="Top" Width="75">
            <i:Interaction.Triggers>
                <local:ButtonClickTrigger>
                    <local:AlertAction/>
                </local:ButtonClickTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</Window>

実行すると、Behaviorの時と同様にButtonをクリックするとMessageBoxが表示されます。

過去記事