【WPF】Behaviorで快適WPFライフ

WPFでゴチャゴチャやってると、ちょっと複雑な処理をやりたくなってくる。で、ちょっと複雑な処理をXAMLに書くのはしんどいな・・・というふうな場合、Behaviorを使うとすごく便利。

Behaviorとはなんだ

これを一言でいうとはとても難しいです。Behaviorは振る舞いとか態度とか作用とか反応とかいう訳語があります。ここでいうBehaviorは作用や反応という訳語が近いでしょうか。振る舞い、などの訳語も遠い意味ではありませんが。

Behaviorでできることは凄くシンプルです。Behaviorの中では、関連付けられた依存オブジェクト(DependencyObject)をコードによっていじくりまわす、ということです。コードビハインドに記述するのに比較すると再利用性が高く、処理がBehaviorの中に綺麗にまとまりますし、テストも容易である、さらにMVVMモデルとの親和性も高い、というあたりが利点でしょうか。

Behaviorを使うには

Behaviorは元々Expression Blend(現Blend for Visual Studio、Professional以上のエディションを買うと付いてくる)のライブラリです。Blendを使って組み込みのBehaviorを組み合わせて複雑な処理をする、という目的で作られましたが、SDKさえあればBlendが無くても使えます。

Expression Blend SDKは適当に検索すると出てきます。現在(2014年6月時点)、バージョン3と4が手に入るようです。3は.NET 3.5に対応していますが、いくつか有用なクラス(CallMethodActionなど)が無いです。可能な限り4を使うと良いでしょう。4は.NET 4.0以上で動作します。

インストールすると、C:\Program Files (x86)\Microsoft SDKs\Expression\Blend以下をたどっていくと、Microsoft.Expression.Interactions.dllとSystem.Windows.Interactivity.dllがありますので、これをプロジェクトから参照します。

実際に使ってみる

TextBoxを用意し、キーが押されるたびに背景色を変えるような動作を実現しましょう。これを素のMVVMでやるのはしんどいですが、Behaviorを使うと簡単に実装できます。以下がXAMLです。TextBoxを一つ配置しているだけです。

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:w="clr-namespace:WPFTest"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        x:Class="WPFTest.MainWindow"
        Title="MainWindow" Height="112" Width="187">
    <Grid>
        <TextBox
			HorizontalAlignment="Left"
			Margin="10,10,0,0"
			VerticalAlignment="Top" Width="101">
            <i:Interaction.Behaviors>
                <w:ColorfulBehavior />
            </i:Interaction.Behaviors>
        </TextBox>

    </Grid>
</Window>

ポイントは、

<i:Interaction.Behaviors>
    <w:ColorfulBehavior />
</i:Interaction.Behaviors>

の部分です。w:ColorfulBehaviorは今回独自に定義したBehaviorです。こいつの中身は以下のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace WPFTest
{
    class ColorfulBehavior : Behavior<TextBox>
    {
        private Random random = new Random();

        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.KeyDown += AssociatedObject_KeyDown;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.KeyDown -= AssociatedObject_KeyDown;
        }

        void AssociatedObject_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            this.AssociatedObject.Background = new SolidColorBrush(
                Color.FromRgb((byte)random.Next(255),
                (byte)random.Next(255),
                (byte)random.Next(255)));
        }
    }
}

Behaviorを自作するには、Behavior<T>を継承したクラスを作ります。ここで、オーバーライドしているOnAttachedとOnDetachingがそれぞれ、対象となるUI要素にBehaviorがアタッチされた時、デタッチされた時の処理になります。普通はここの瞬間にとりたいイベントに対してハンドラを設定することになります。

また、this.AssociatedObjectが、このBehaviorがアタッチしているUI要素になります。型はTになります。

ここでは、KeyDownを取り、KeyDownが発火したら背景色をランダムに変化させるようなコードを書きました。

実行結果が以下です。

ちゃんと変わってますね。

バインドもできる

BehaviorはDependencyObjectを継承しているので、当然、依存プロパティが使えます。依存プロパティが使えるという事はバインドもできるという事です。

今回のようなことをやるだけなら、正直、コードビハインド書いてもあまり違いは無いと思いますがバインドなどを使えばコードビハインドでやるよりももっといろいろなことが可能になるでしょう。

 追記

「今でもExpression Blend SDKを使わなきゃならないのかな・・・」というコメントをいただきました。調べてみましたところ、NuGetでは取ってこれるみたいです。

Blend Interactivity for WPF v4.0

ただし、v4なので、.net 3.5上でやりたい場合はやっぱりSDKを入れなければならないと思います。

.NET 標準で搭載しても良いような気がするのですが、どうなんでしょうね。WPFは自由度が高すぎていまいち設計やコーディングの標準化が難しいような気がします。