UWPのListViewからMVVMのModelをいじるお話
ListViewのItemにあるTextBoxの値を書き換えるとバインド元のModelも書き換わるようなUWPのMVVMのサンプルコードを書いてみました。
実行スクリーンショット
1. 初期状態
最初にModelに入れた[0,1,2,3,4]がTextBoxに列状に表示されます。
上部の「Output」ボタンを押すとVMの元になっているModelのデータが書き出されます。
2. 初期状態から「Output」ボタンを押したとき
下のTextBlockにModelの値が横並びで表示されます。
3.TextBoxの値を変えて「Output」ボタンを押したとき
3行目のTextBoxの値を2から10に書き換えたところModelのデータもそのように書き換わりました。
クラス図
今回の実装に当たり書いたプログラム同士の関係は下図のとおりです。
MainViewModelがModelとなるNumbersListのインスタンスをもち、そのNumbersListは実値を保持するNumberのインスタンスを格納したCollectionを持ちます。
またMainViewModelは実値を取得するためのNumberViewModelのCollecctionを持ち、そのNumberViewModelはNumberから得られる実値を持っています。
使用したライブラリ
- Reactive Property v5.3.0(2018年11月14日現在最新版)
個人的にはまったこと
Model自体がコレクションを持っているようなクラスをViewModelにする場合、そのコレクション先のインスタンス毎に対してViewModelインスタンスを作り、それをModelと紐づけしてあげないとBindingがうまくいかないようです。
//Bindingのサンプル public class MainViewModel : Observable { private NumbersList Model { get; set; } public ReadOnlyReactiveCollection<NumberViewModel> numbers { get; } public ReactiveProperty<String> Output { get; set; } public MainViewModel() { Model = new NumbersList(); Output = new ReactiveProperty<string>(""); numbers = Model.NumsList.ToReadOnlyReactiveCollection(x => new NumberViewModel(x)); } }
たとえば、MainViewModelから直接Modelのコレクションをバインディングした場合にはModelからViewModelへのデータ遷移がおこなわれていないようです
//これだとModel→ViewModelがダメ public class MainViewModel : Observable { private NumbersList Model { get; set; } public ReadOnlyReactiveCollection<int> numbers { get; } public ReactiveProperty<String> Output { get; set; } public MainViewModel() { Model = new NumbersList(); Output = new ReactiveProperty<string>(""); numbers = Model.NumsList.ToReadOnlyReactiveCollection(x => x.Num); } }
ソースコード
今回作成したコードはGitHubにて公開しています。
github.com