読者です 読者をやめる 読者になる 読者になる

開発記その 1 - VM のメソッド呼び出し -

MoneyBook の開発に着手しました。

MoneyBook は複数のユーザーで使うことを想定しているので、 ASP.NET の Membership を使ってログイン画面かなと思ったのですが、そもそもユーザー登録する画面も欲しくなったので、まずは登録画面から作りはじめました。テキストボックスが並んでボタンを押したらユーザーが作成される普通の画面です。


ボタンを押したら VM のメソッドを呼んで処理を行うわけですが、 WPF とかだったら Command を使うところですが実はあんまり好きじゃない。わざわざ Command にデリゲートを設定して、公開するっていう手間がかかるし、気持ち的には一発で VM のメソッドを呼んで欲しいわけです。しかも Silverlight の Command は今のところボタンのクリックにしか対応してないので、いまいち。


と、いうことで他の手段を考えるわけですが、実は Expression BlendSDK に CallMethodAction ってのがあります。こいつは任意のオブジェクトのメソッドを呼び出してくれる Action です。以下のような感じ。

こいつの TargetObject に Binding を使って、ルート要素なりなんなりの DataContext を指定すれば、その DataContext に設定されている VM のメソッドが呼ばれるってわけです。

{Binding ElementName=LayoutRoot,Path=DataContext}

Blend で設定できるし、VM のメソッドを一発で呼び出してくれるのでいい感じですね。さらにボタンのクリックだけじゃなくって Trigger の内容次第で呼び出したいタイミングを自由に設定できるので、例えば ListBox の SelectionChanged なんかでも OK です。

が、今回はちょっと思うところあって車輪の再発明になりますが、同じ機能のものを別に作りました。思うところってのはまた後日。それが以下の InvokeMethodAction です。ただ単純に指定されたメソッドをリフレクションで探し出して呼び出してるだけです。

[DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), "MouseLeftButtonDown")]
[DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), "Click")]
[DefaultTrigger(typeof(Selector), typeof(System.Windows.Interactivity.EventTrigger), "SelectionChanged")]
public class InvokeMethodAction : TriggerAction<FrameworkElement> {

  public InvokeMethodAction() {
  }

  public object Target {
    get { return (object)GetValue(TargetProperty); }
    set { SetValue(TargetProperty, value); }
  }

  public static readonly DependencyProperty TargetProperty =
    DependencyProperty.Register("Target", typeof(object), typeof(InvokeMethodAction), null);

  public string MethodName { get; set; }

  protected override void Invoke(object parameter) {
    if (this.Target == null || string.IsNullOrWhiteSpace(this.MethodName)) {
      return;
    }
    Type targetType = this.Target.GetType();
    MethodInfo method = targetType.GetMethod(this.MethodName, BindingFlags.Public | BindingFlags.Instance);
    if (method == null) {
      throw new InvalidOperationException(String.Format(ErrorMessages.TargetMethodNotFound,this.MethodName));
    }
    method.Invoke(this.Target, null);
  }
}

DefaultTriggerAttribute を指定してあげておくことで、 Blend で Action を落としたときに自動で設定される Trigger を指定することができます。

※今回のチェックイン
http://moneybook.codeplex.com/SourceControl/changeset/changes/51093