この回の手順は失敗。解決法が分かったので次回記事にまとめる。
Modelの変更をViewへ通知するには?
Model(TestDataクラス)の値をプログラム内部で変更したとしてもView(MainWindow)には反映されない。
反映させるには、ModelからViewへ変更を通知しなければならない。
例えば、前回までのソースで、ボタンをクリックする毎にchecked値を反転させる処理に変更する。
■ViewModel.vb
ということで、ItemDataクラスでcheckedプロパティの変更があれば、親クラス(TestDataクラス)へ通知、
さらにTestDataはViewModelへ変更通知を、ViewModelからViewへの変更通知を行うようにする。
ItemDataはコレクション(List)として格納されている。
ItemDataからTestDataへの変更通知をどうすれば良いか?
いい案が浮かばないので、ItemDataに親のTestDataオブジェクトを持たせ、ItemDataからTestDataのメソッドを呼び出すことにした。
このためのインターフェースクラス(INotify.vb)を作成、
メソッドとしては子からの変更を受け取るメソッド "ChildrenPropertyChanged" を作成する。
■INotify.vb
ItemDataクラスでcheckedプロパティ値に変更が発生したらINofityインターフェースのChildrenPropertyChangedメソッドを呼び出すように修正。
また親オブジェクトをコンストラクタで取得するように修正。
■ItemData.vb
TestDataクラスはINotifyインターフェースを継承する。
またTestDataからViewModelへの変更通知は System.ComponentModelのINotifyPropertyChangedインターフェースを継承することで対応。
ItemDataオブジェクト生成時に自身のインスタンスを渡すように修正。
■TestData.vb
ViewModelはSystem.ComponentModelのINotifyPropertyChangedインターフェースを継承、Model変数はWithEvents付きで宣言し、Modelからの変更を受信できるようにする。
■ViewModel.vb
反映させるには、ModelからViewへ変更を通知しなければならない。
例えば、前回までのソースで、ボタンをクリックする毎にchecked値を反転させる処理に変更する。
■ViewModel.vb
Private Sub _ClickEvent_ShowMessage(id As Integer) Handles _ClickEvent.ShowMessage
For Each item In Model.items.Where(Function(x) x.id = id)
item.checked = item.checked Xor True
Next
End Sub
これでボタンクリックすれば選択のチェックボックスが付いたり消えたりする筈だが、そうはならない。ということで、ItemDataクラスでcheckedプロパティの変更があれば、親クラス(TestDataクラス)へ通知、
ItemDataはコレクション(List)として格納されている。
ItemDataからTestDataへの変更通知をどうすれば良いか?
いい案が浮かばないので、ItemDataに親のTestDataオブジェクトを持たせ、ItemDataからTestDataのメソッドを呼び出すことにした。
このためのインターフェースクラス(INotify.vb)を作成、
メソッドとしては子からの変更を受け取るメソッド "ChildrenPropertyChanged" を作成する。
■INotify.vb
Public Interface INotify
Sub ChildrenPropertyChanged(Name As String, Value As Object)
End Interface
※ 引数はプロパティ名(Name)だけでも良いが、何か使うかもしれないのでプロパティ値(Value)も付けておいた。ItemDataクラスでcheckedプロパティ値に変更が発生したらINofityインターフェースのChildrenPropertyChangedメソッドを呼び出すように修正。
また親オブジェクトをコンストラクタで取得するように修正。
■ItemData.vb
Public Class ItemData
Private _Parent As INotify
Public Property id As Integer
Public Property name As String
Public Property subitems As New List(Of SubItemData)
Private _checked As Boolean = True
Public Property checked As Boolean
Get
Return _checked
End Get
Set(value As Boolean)
If (_checked <> value) Then
_checked = value
_Parent.ChildrenPropertyChanged("checked", _checked)
End If
End Set
End Property
Public Sub New(Parent As INotify)
_Parent = Parent
End Sub
End Class
TestDataクラスはINotifyインターフェースを継承する。
またTestDataからViewModelへの変更通知は System.ComponentModelのINotifyPropertyChangedインターフェースを継承することで対応。
ItemDataオブジェクト生成時に自身のインスタンスを渡すように修正。
■TestData.vb
Imports YamlDotNet.RepresentationModel
Imports System.ComponentModel
Public Class TestData
Implements INotify, INotifyPropertyChanged
:
Public Sub Load()
:
For Each itemNode In DirectCast(children.Item(New YamlScalarNode("items")), YamlSequenceNode)
Dim item As New ItemData(Me)
:
Next
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Sub ChildrenPropertyChanged(Name As String, Value As Object) Implements INotify.ChildrenPropertyChanged
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Name))
End Sub
ViewModelはSystem.ComponentModelのINotifyPropertyChangedインターフェースを継承、Model変数はWithEvents付きで宣言し、Modelからの変更を受信できるようにする。
■ViewModel.vb
Imports System.ComponentModel
Public Class ViewModel
Implements INotifyPropertyChanged
Private WithEvents _Model As New TestData()
Public ReadOnly Property Model As TestData
Get
Return _Model
End Get
End Property
Private Sub _Model_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Handles _Model.PropertyChanged
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(e.PropertyName))
End Sub
:
次回記事:VisualBasic+WPF+YAML #13:Modelの変更をViewへ通知する 2
-- 以上 --
VisualBasic, WPF, DataGrid, YAML, MVVM
0 件のコメント:
コメントを投稿