2010年10月04日

Windows Phone 7:MVVM Light Toolkitを使ってみた

 MVVMについては「MVVM Light Toolkitを使ってみよう。その2 MVVMの復習」とかるあさんが上級者向けの良エントリを展開してくれているので私はできるだけ初心者向けに噛み砕いてMVVMについての考察を行っていこうと思う。

xamlとC#コードを切り離すのがMVVMだ



 極論、C#コードからxamlを操作する部分を無くして独立でテスト可能なコードすることがMVVMの肝だ。


 例えば以下のようなコードがあるとする。

xaml側
<Button Content="Button" Click="button1_Click">


C#コード
private void button1_Click(object sender, RoutedEventArgs e)
{
  // xamlから値を取り出す
  Person.name = this.nameText.Text;
  Person.age = int.Perse(this.ageText.Text);

  // Webなどに通信して保存するようなコード
  Service.save(Person);

}


 よくあるボタンイベントを引き金にしてデータを保存するようなコードだと思ってほしい。

 このコードでは

  Person.name = this.nameText.Text;
  Person.age = int.Perse(this.ageText.Text);


 がxamlコードの引き離せていない部分だ。

 C#側はxamlにnameText、ageTextというTextBox(もしくはTextプロパティを持ったコントロール)がありそのTextプロパティからname、ageを取得しなければならないことを知っていないといけない

 このコードを以下のように書けるとxamlコードから切り離せる。

private void button1_Click(string text, int age)
{
  // xamlからではなくメソッドの引数としてもらった
  Person.name = text;
  Person.age = age;

  // Webなどに通信して保存するようなコード
  Service.save(Person);

}


 このような変更を可能にするのがコマンドバインディングだ。

コマンドとバインディング



 Silverlight開発者にとってバインディングは既存の機能だ。

 自分も以前にバインディングについての記事を書いたので参考にして欲しい(ネット上にはもっとわかりやすい記事もある)。

 Silverlight:データバインディング入門

 バインディングがC#コードのプロパティとxamlの値を関連付ける仕組みを提供してくれる。

 コマンドはSilverlight的には新しい概念だ。
 xaml側からイベントハンドラより自由にc#コードを呼び出す(コマンドを送る)仕組みだ。

 コマンドはSilverlight4からの機能でSilverlight3ベースのWindows Phone 7でコマンドを使うには、今のところMVVM Light Toolkitを必要とする。

 これで相互のデータのやりとり、xaml側からのメソッドを呼び出しの仕組みが提供された。あとは実際にどう操作するのかをコードを交えて紹介していきます。

MVVM Light Toolkitのインストール



 MVVM Light Toolkitはcodeplexで公開されているが使い方等はgalasoftにある。

 まずはcodeplexの右上のDownloadボタンからファイルをダウンロードしよう。
 (現時点でのファイル名はGalaSoft.MvvmLight.V3SP1.zip)

 ファイルを展開すると以下のようなファイルが解凍される。

001


 Windows Phone 7用のテンプレートとしてGalaSoft.MvvmLight.Templates.V3.VS10X.zipがあるがbeta版時点のもので現在は利用できない。
 とりあえずライブラリだけ利用するのでGalaSoft.MvvmLight.Binaries.V3.zipを更に展開する。

 展開したファイルのLaurent Bugnion (GalaSoft)\Mvvm Light Toolkit\Binaries\WP7以下に必要なdllファイルがある。

002


 上画像の.dll拡張子のファイルをWindows Phone 7プロジェクトの参照に追加すればMVVM Light Toolkitを利用する準備が整った。

003


バインディングサンプル



 MVVM(Model-View-ViewModel)はModelとViewという既存の概念にコントロールの代わりにViewModelを用いる。
 Windows Phone 7のPanoramaなどを利用する場合はデフォルトのプロジェクトにViewModelディレクトリが生成されるので目にしたことがある方も多いはず。

 MVVM Light ToolkitのViewModelはViewModelBaseクラスを継承する。

 004


 ViewModelクラスの詳細に入る前にこのクラスをViewに関連付ける方法の一例を紹介する(やり方は色々あると思う)。

 MainPage.xamlの先頭PhoneApplicationPageタグに以下を追加する。

xmlns:ViewModel="clr-namespace:MVVMSample.ViewModels"
xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"


 MVVMSampleというプロジェクトのViewModelsディレクトリ以下にViewModelファイルを配置しているので、

xmlns:ViewModel="clr-namespace:MVVMSample.ViewModels"

 となっている。ここは作成したプロジェクトにあわせて書き換えて欲しい。

 次にViewModelをリソースとして利用可能できるようにする。

<UserControl.Resources>
  <ViewModel:MainPageViewModel x:Key="viewModel" />
</UserControl.Resources>

 これでkeyであるviewModelでMainPageViewModel.csクラスが利用できる。

 
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{StaticResource viewModel}">


 DataContextにviewModelをセットしています。

 
<TextBox Name="textBlock1" Text="{Binding user.name, Mode=TwoWay}" />


 MainViewModelクラスのuserプロパティのnameプロパティにバインドされました。

 xaml側のコードだけでMainViewModelを関連付ることができました。
 相互がまったくお互いを知らないというのは難しい話で今回の場合も、関連付ける必要があるクラス、そしてプロパティとしてuser.nameが取得できることを知っている必要はあります。 

コマンドサンプル



 次はボタンクリック時にClickイベントハンドラではなくてCommandを使うサンプルを紹介。

<TextBox Height="73" HorizontalAlignment="Left" Margin="51,57,0,0"
Name="textBlock1" Text="{Binding user.name, Mode=TwoWay}" VerticalAlignment="Top" Width="302" RenderTransformOrigin="0.5,0.5" >
</TextBox>

<Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="70,195,0,0" Name="button1" VerticalAlignment="Top" Width="209" Click="button1_Click">
  <Interactivity:Interaction.Triggers>
    <Interactivity:EventTrigger EventName="Click" x:Name="btnSearchClickedEventTrigger">
      <Command:EventToCommand Command="{Binding testCommand}" CommandParameter="{Binding Text, ElementName=textBlock1}"/>
    </Interactivity:EventTrigger>
  </Interactivity:Interaction.Triggers>
</Button>

 注目するのは

 Command:EventToCommand Command="{Binding testCommand}" CommandParameter="{Binding Text, ElementName=textBlock1}"

 の部分。
 Command名前空間は先にPhoneApplicationPageに追加しましたね。

 Command="{Binding testCommand}"がtestCommandを呼び出すという意味で、
 CommandParameter="{Binding Text, ElementName=textBlock1}"がパラメーターとしてtextBlock1のTextプロパティの値を送信するという意味です。

 続いてC#側MainViewModel.csを見てみましょう。
 必要最低限しか記述していないのでこちらは全文を載せます。

006

(クリックで拡大)

public RelayCommand<string> testCommand


 testCommandは上のように定義されており、コンストラクタでそこにRelayCommandクラスを代入しています。

this.testCommand = new RelayCommand<string>((string name) => this._testCommand(name), (param) => { MessageBox.Show(param); return true; });

 RelayCommandクラスに渡すコンストラクタ引数の一つ目が実行されるクラスの実装。2つめが実行する条件判定です。
 2つめのメソッドは現在かならずtrueを返すようになっていますが、ここで判定を行いfaleseを返すと一つ目の引数で指定されたメソッドが実行されません。

 詳しい使い方は

 Using RelayCommands in Silverlight 3 and WPF

 を参照してください。

 以上、駆け足気味でしたがWindows Phone 7+MVVM Light ToolkitでViewModelのバインドとコマンドの呼び出しを行う方法を紹介しました。

 私自身まだMVVMについて触りながら覚えている状態なので他の方のエントリなどと合わせて読まれると良いと思います。

 次回はせっかく依存を無くしたんだからテストコードを書いてみよう的なアプローチで行こうかな。

トラックバックURL

トラックバック一覧

1. Windows Phone 7:MVVM Light Toolkitを使ってみた  [ .NET Clips ]   2010年10月05日 00:35
素敵なエントリーの登録ありがとうございます - .NET Clipsからのトラックバック

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
Profile

シーラカンス

Recent Comments
QRコード
QRコード
livedoor Readerに登録
RSS
livedoor Blog(ブログ)