この回の手順は失敗。解決法が分かったので次回記事にまとめる。
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 件のコメント:
コメントを投稿