MVVM List Detail パターン
コード
ListDetail
今まで、ListとDetailをその都度、ああでもない、こうでもないと試行錯誤して書いていたので、パターンにまとめてみました。
開発環境
.NET Core 3.1 + ReactiveProperty で構築します。
ListViewModelとDetailViewModel
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
になります。
<Button Command="{Binding DataContext.ButtonShow, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}">Show</Button>
public ReactiveCommand<DetailViewModel> ButtonShow { get; } = new ReactiveCommand<DetailViewModel>();
その行のDetailViewModel
自体をパラメータとしてうけとり(ここではxが、パラメータ)
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はそれぞれ異なります。
DataGridの行で利用している、同じDetailViewModelを利用して、Detailを表示したいなら、
private void ShowDetail(DetailViewModel infoVM)
の段階で、infoVMを利用して、ListViewModel.cs
から、DetailViewを表示してもいいかもしれません。そうすると、DataGridの行と新しく表示したDetailViewでのDataContext
は、同じDetailViewModel
を利用することになるでしょう。
Remove
Showとほぼ同じです。
newの順序
Model → ViewModel → View の順序でnewしています。
var list = new ListManager();
ViewController.ShowListView(list);
ViewとViewModelのnewは、ViewController
のpublic static
のクラスで処理することにしました。
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
DataGridのClear・Removeは、ListManager.cs
のObservableCollection<Info> InfoList
を、Clear
したりRemove
しています。
すると、ListViewModel
の、ReadOnlyReactiveCollection<DetailViewModel> InfoList
が変更されます。このコードでは、すぐに、DetailViewModel
もDispose
されたので、ここでは明示的にはDetailViewModel
のDispose
を呼び出していません。(これで良いのか?がよくわかりません。)
DetailのViewModel
DetailView
をClose
した時は、Dispose
されるのかどうかが分からないので、明示的にDipose
しています。
private void Close()
{
CloseAction();
Dispose();
}
感想
処理の流れがはっきりせず、デバッグしつつ追わないと、コードを見るだけでは分かりませんね。この点が、MVVMの難しいところだと思います。
ただ、パターン化しておくと、処理の流れの見当が少しつきやすくなりますね。
MVVMの記事
- パターン1 Viewのコードビハインド
- パターン2 Commandパラメータ
- パターン3 Prism の Dialog Service
Author And Source
この問題について(MVVM List Detail パターン), 我々は、より多くの情報をここで見つけました https://qiita.com/hiro_t/items/2c843a8b2117573d9bfa著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .