MVVM List Detail パターン

## コード
### ListDetail
https://github.com/mikihiro-t/MVVMPattern

今まで、ListとDetailをその都度、ああでもない、こうでもないと試行錯誤して書いていたので、パターンにまとめてみました。

### 開発環境
.NET Core 3.1 + ReactiveProperty で構築します。

## ListViewModelとDetailViewModel
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/f9909908-c32d-8733-8200-d4c99753c3a3.png)

```C#:ListViewModel.cs
this.InfoList = this.Model.InfoList.ToReadOnlyReactiveCollection(x => new DetailViewModel(x)).AddTo(Disposable);
```

で、**DataGridのそれぞれの行に対応する、それぞれの`DetailViewModel`を作成**しています。
MVVMを学び始めた当初、DataGridやListViewではこうする方法があることが分からなかったですね。

## Show
ShowボタンのXAMLは次です。
Commandは、DataGridの`DataContext`つまり、Windowの`DataContext`（=`ListViewModel`）の`ButtonShow`を呼び出します。
パラメータは、`CommandParameter="{Binding}"`によって、この行の`DetailViewModel`になります。

```C#:ListView.xaml
<Button Command="{Binding DataContext.ButtonShow, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}">Show</Button>
```


```C#:ListViewModel.cs
public ReactiveCommand<DetailViewModel> ButtonShow { get; } = new ReactiveCommand<DetailViewModel>();
```

**その行の`DetailViewModel`自体をパラメータとしてうけとり**（ここではxが、パラメータ）

```C#:ListViewModel.cs
ButtonShow.Subscribe(x => ShowDetail(x)).AddTo(Disposable);

private void ShowDetail(DetailViewModel infoVM)
{
    Model.ShowDetail(infoVM.Model);
}
```

`DetailViewModel`が保持している`Model（infoVM.Model）`を、`ListManager`に渡して、`Detail`を表示します。

従って、DataGridの行でもDetailでも、Modelは同じものを参照しますが、VMはそれぞれ異なります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/180ed082-0919-f61d-e3e7-ab138d14ed5e.png)

DataGridの行で利用している、同じDetailViewModelを利用して、Detailを表示したいなら、

```C#:ListViewModel.cs
private void ShowDetail(DetailViewModel infoVM)
```

の段階で、infoVMを利用して、`ListViewModel.cs`から、DetailViewを表示してもいいかもしれません。そうすると、DataGridの行と新しく表示したDetailViewでの`DataContext`は、同じ`DetailViewModel`を利用することになるでしょう。

## Remove
Showとほぼ同じです。

## newの順序
Model　→　ViewModel 　→　View　の順序でnewしています。

```C#:Main.cs
var list = new ListManager();
ViewController.ShowListView(list);
```

ViewとViewModelのnewは、`ViewController`の`public static`のクラスで処理することにしました。

```C#:ViewController.cs
public static void ShowListView(ListManager model)
{
    var viewModel = new ListViewModel(model);
    var view = new ListView(viewModel);
    view.Show();
}
```

View　 →　ViewModel　→　Model の方法もありますが、ここではModelが先です。
バックグラウンドでModelが動いていて、ある条件でViewを表示するなら、Modelを先にせざる得ないでしょうし、Modelが無くてVとVMだけあることはMVVMでは考えにくいので、Modelを先にnewするのがいいのではという考えです。

## Disposeのタイミング
`ReactiveProperty`で、よく分からないのは`Dispose`を呼び出すタイミングです。

### DataGridのViewModel
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/586aff25-cc97-c02e-eef0-d45c32e9796f.png)

DataGridのClear・Removeは、`ListManager.cs`の`ObservableCollection<Info> InfoList`を、`Clear`したり`Remove`しています。
すると、`ListViewModel`の、**`ReadOnlyReactiveCollection<DetailViewModel> InfoList`**が変更されます。このコードでは、すぐに、`DetailViewModel`も`Dispose`されたので、ここでは明示的には`DetailViewModel`の`Dispose`を呼び出していません。（これで良いのか？がよくわかりません。）

### DetailのViewModel
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/827e1cb6-a2ce-28f8-8c75-8cc524e15d5c.png)

`DetailView`を`Close`した時は、`Dispose`されるのかどうかが分からないので、**明示的に`Dipose`**しています。

```C#:DetailViewModel.cs
private void Close()
{
    CloseAction();
    Dispose();
}
```

## 感想
処理の流れがはっきりせず、デバッグしつつ追わないと、コードを見るだけでは分かりませんね。この点が、MVVMの難しいところだと思います。
ただ、パターン化しておくと、処理の流れの見当が少しつきやすくなりますね。

## MVVMの記事
* パターン1　[Viewのコードビハインド](https://qiita.com/hiro_t/items/967146f2ccb79318397c)
* パターン2　[Commandパラメータ](https://qiita.com/hiro_t/items/b177c40e03d22ef24068)
* パターン3　[Prism の Dialog Service](https://qiita.com/hiro_t/items/61a50d9f6308195c3536)