件名からはわかりづらいですが、ViewからViewModelに対し、命令(コマンド)を実行させる、
従来でいうところのイベントの受け渡し方法についてさらっと説明します。
結構厄介なので、前置きはこれくらいにして本題に入ります。
今回も同じく
前回「WPF ViewからViewModelへの値受け渡し方法 」の
ソースコードありきで進めます。
1. さっそくですが、命令をやり取りするためにはICommandインターフェイスを実装したクラスが必要になるのですが、
デフォルトではこのようなクラスがないので、自作しなければいけません。
これは、ほとんど定型文のようなクラスで、こう書く以外にあまり方法はないのですが、
MSDNにあるコードを、ほぼそのままブログに記載するのは気が引けるため、本文からはずします。
ここをクリックすると該当コードのみ見れますので、すみませんがここにあるクラスをまんま生成してください。
( 参考サイト:MSDN Model-View-ViewModel デザイン パターンによる WPF アプリケーション
(
http://msdn.microsoft.com/ja-jp/magazine/dd419663.aspx2.ViewModel側には、命令をバインディングするためのプロパティと、実ロジックを記述します。
前回の画面で、意味ありげに「クリア」というボタンを作りましたので、クリア処理を実装するものとします。
以下のプロパティを追加。
Private _resetCommentCommand As ICommand
Public Property ResetCommentCommand() As ICommand
Get
Return _resetCommentCommand
End Get
Set(ByVal value As ICommand)
_resetCommentCommand = value
End Set
End Property
以下の実ロジックを追加。
Private Sub ResetCommentCommandCore()
Me.Comment = ""
End Sub
コンストラクタで、命令プロパティをセットする。(おまじないだと思って下さい)
Me.ResetCommentCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.ResetCommentCommandCore))
3.ViewModelに作成した命令プロパティと、Viewのボタンクリックとを関連付けましょう。
これも決まりごとなので、以下のように書いてください。
<Button Content="リセット" Command="{Binding ResetCommentCommand}" />これで完成です。
早速デバッグしてみましょう。
うまくいけば、「クリア」ボタンを押したときに、テキストボックスの文字が全て消えるはずです。
が、消えません。CommentプロパティのSetterにブレークポイントを設置すると、ちゃんと空文字が代入されているはずなんですが、
画面上には反映されませんねぇ。
4.実はViewModel内のプロパティを更新しても、Viewは変更されたことに気づけないのです。
Viewに気づかせるためには、ViewModelで INotifyPropertyChanged インターフェイスを実装する必要があります。
これは定型文で実装できますので、以下のコードをSampleViewModelに追加してください。
(Implementsですので、Public Class SampleViewModelの次の行に記述してください)
Implements ComponentModel.INotifyPropertyChanged '変更通知をサポートしていること示すインターフェイス
#Region "INotifyPropertyChangedの実装"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
''' <summary>
''' プロパティに変更が発生したことを通知します。
''' </summary>
Private Sub OnPropertyChanged(ByVal propertyName As String)
Dim e As New System.ComponentModel.PropertyChangedEventArgs(propertyName)
RaiseEvent PropertyChanged(Me, e) '変更通知イベントを発生させる。
End Sub
#End Region
5.通知処理は実装できましたので、変更が発生した場合に「4」で作った関数をコールするようにしましょう。
つまり、PropertyのSetter処理が走ったら、コールすればOK。
具体的には以下のコードになる。
Public Property Comment() As String
Get
Return _comment
End Get
Set(ByVal value As String)
_comment = value
Me.OnPropertyChanged("Comment") '変更を通知
End Set
End Property
これで完成。デバッグを実行して、クリア処理ができていることを確認してみよう。
以上でViewModel→View、View→ViewModelの連携はさらっと一通り終了。
あとはBindingについての知識を深めることで、いろいろな応用ができる。
これについてはそのうち記事にできればと思います。
完成バージョンのソースコードは
こちら。
補足
通常、ViewModelではINotifyPropertyChangedインターフェイスを実装することが必須となります。そして、ViewModelを担当するクラスが1つだけということもほぼありません。しかも、INotifyPropertyChangedの実装は定型文です。
ということは、各クラス個別に記述するのは非効率な上、バグの王将になります。基底クラスを作り、そちらで管理したほうがすっきりするでしょう。