ikarosの作業場

飛行機の設計もできる系のプログラマー。なおこの記事は個人的見解であり、所属する組織の意見とは一切関係がありません

UWPのListViewからMVVMのModelをいじるお話

ListViewのItemにあるTextBoxの値を書き換えるとバインド元のModelも書き換わるようなUWPのMVVMのサンプルコードを書いてみました。

実行スクリーンショット

1. 初期状態

f:id:ikarostech:20181114160518p:plain
最初にModelに入れた[0,1,2,3,4]がTextBoxに列状に表示されます。
上部の「Output」ボタンを押すとVMの元になっているModelのデータが書き出されます。

2. 初期状態から「Output」ボタンを押したとき

f:id:ikarostech:20181114161152p:plain
下のTextBlockにModelの値が横並びで表示されます。

3.TextBoxの値を変えて「Output」ボタンを押したとき

f:id:ikarostech:20181114161421p:plain
3行目のTextBoxの値を2から10に書き換えたところModelのデータもそのように書き換わりました。

クラス図

今回の実装に当たり書いたプログラム同士の関係は下図のとおりです。
f:id:ikarostech:20181114160155p:plain

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

参考にしたサイト

blog.okazuki.jp

当サイトのソースコード及びその他の情報は個人・商用問わず自由に使っていただいてかかまいませんが、当サイトの情報が元で発生したいかなる結果・不利益については責任を負いかねますのでご了承ください