APR
24

※今回のエントリはWPFでの話ですが、Silverlightでも参考になると思います。

Expression Blend 3で追加されたBehavior、元はと言えば、Attached Behavior(添付ビヘイビア)という名前でWPF/Silverlight開発者の間で親しまれていたパターンが、Expression Blend 3でデザイナのサポートを受けれるようになったものです。

添付ビヘイビアとは、内部的には添付プロパティを利用し、添付された要素への参照を得ることでそのイベントを購読し、そのイベントハンドラにおいて、オブジェクトに対する様々な操作を実現する便利なテクニックです。

BehaviorがExpression Blendでサポートされたことにより、要素に対する添付ビヘイビアの追加、削除を、コードを書かずにGUI操作だけでできるようになりました。また、Microsoft.Expression.Interactivity.dll内の抽象クラスを利用することで、実装もより容易になっています。

image

Preview版では現在のところBehaviorはExpression Blendに付属しておらず、別途ダウンロードしてきて参照に加えることが必要ですが(Sample Silverlight 3 Behaviors(Silverlight)やMicrosoft Expression Community Gallery)、自分で書いたBehaviorを使うことももちろん可能です。 今回は試しにBehaviorを自分で書いてみました。お題は以前書いた添付ビヘイビアでTextBoxにCommandを実装してみた – SharpLab.の再実装。

まずは<Expression Blend3 Previewのインストールディレクトリ>\Libraries\WPF以下に存在するMicrosoft.Expression.Interactivity.dllを参照を加えます。このアセンブリに含まれているBehavior<T>や、TriggerAction<T>などが、Behaviorを作る上での基本クラスとなるようです(他にもあるようですが、まだ追えていません)。さて、今回はTextBoxに添付するBehaviorなので、Behavior<TextBox>を継承したクラスを作ります。

using System.Windows;
using System.Windows.Input;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls;

namespace SharpLab.IKnow.ItemBankPane {
	public class ExecuteCommandOnEnterKeyDownBehavior : Behavior<TextBox> {
	}
}

続いて、アタッチ/デタッチされる時に実行されるOnAttach/OnDetachingメソッドを作成します。AssociatedObjectプロパティに添付対象の要素が入っているので、ここからイベントの購読/購読解消を行います。

using System.Windows;
using System.Windows.Input;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls;

namespace SharpLab.IKnow.ItemBankPane {
	public class ExecuteCommandOnEnterKeyDownBehavior : Behavior<TextBox> {

		protected override void OnAttached() {
			base.OnAttached();

			this.AssociatedObject.KeyDown += OnKeyDown;
		}

		protected override void OnDetaching() {
			base.OnDetaching();

			this.AssociatedObject.KeyDown -= OnKeyDown;
		}

		void OnKeyDown(object sender, KeyEventArgs e) {
		
		}
	}
}

さて、今回はCommandをEnterキーが押された時に実行するのが目的なので、まずはCommandを受け取れるように依存関係プロパティを実装します。

using System.Windows;
using System.Windows.Input;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls;

namespace SharpLab.IKnow.ItemBankPane {
	public class ExecuteCommandOnEnterKeyDownBehavior : Behavior<TextBox> {

		public string Command {
			get {
				return (string)GetValue(CommandProperty);
			}
			set {
				SetValue(CommandProperty, value);
			}
		}

		public static readonly DependencyProperty CommandProperty =	
									DependencyProperty.Register("Command",
										typeof(string),
										typeof(ExecuteCommandOnEnterKeyDownBehavior));

		protected override void OnAttached() {
			base.OnAttached();

			this.AssociatedObject.KeyDown += OnKeyDown;
		}

		protected override void OnDetaching() {
			base.OnDetaching();

			this.AssociatedObject.KeyDown -= OnKeyDown;
		}

		void OnKeyDown(object sender, KeyEventArgs e) {
		}
	}
}

Enterキーが押された時に、Commandが実行されるようにします。

using System.Windows;
using System.Windows.Input;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls;

namespace SharpLab.IKnow.ItemBankPane {
	public class ExecuteCommandOnEnterKeyDownBehavior : Behavior<TextBox> {

		public string Command {
			get {
				return (string)GetValue(CommandProperty);
			}
			set {
				SetValue(CommandProperty, value);
			}
		}

		public static readonly DependencyProperty CommandProperty =	
									DependencyProperty.Register("Command",
										typeof(string),
										typeof(ExecuteCommandOnEnterKeyDownBehavior));

		protected override void OnAttached() {
			base.OnAttached();

			this.AssociatedObject.KeyDown += OnKeyDown;
		}

		protected override void OnDetaching() {
			base.OnDetaching();

			this.AssociatedObject.KeyDown -= OnKeyDown;
		}

		void OnKeyDown(object sender, KeyEventArgs e) {
			if (e.Key == Key.Enter) {
				string path = Command;
				object dataContext = AssociatedObject.DataContext;
				ICommand command = dataContext.GetType().GetProperty(path).GetValue(dataContext, null) as ICommand;

				if (command != null && command.CanExecute(AssociatedObject)) {
					command.Execute(AssociatedObject);
				}
			}			
		}
	}
}

これで完成しました!…と言いたいところですが、どうもMicrosoft.Expression.Interactivity.dllのバグか、これだけではコンパイルが通りません。どうもアセンブリ内にMicrosoft.Expression.Interactivity.Layout名前空間がないとコンパイルが通らないようで、適当にdummy.csというファイルを作っておき、

namespace Microsoft.Expression.Interactivity.Layout {}

と一行書いておきましょう。

image

これで、作成したBehaviorを参照に加えれば、AssetLibraryのBehaviorsタブに作ったBehaviorが追加されるようになります。

image

あとは要素にD&Dで添付した上で、プロパティペインから、諸々のプロパティを設定すれば使えるようになります。