■ VisualBasic+WPF+YAML #12:Modelの変更をViewへ通知する

VBからYMALファイルを読み込みたい。
前回記事:VisualBasic+WPF+YAML #11:DataGridのイベント 4

この回の手順は失敗。解決法が分かったので次回記事にまとめる。



Modelの変更をViewへ通知するには?

Model(TestDataクラス)の値をプログラム内部で変更したとしてもView(MainWindow)には反映されない。
反映させるには、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クラス)へ通知、 さらにTestDataはViewModelへ変更通知を、ViewModelからViewへの変更通知を行うようにする。

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 件のコメント:

その他の記事