MVVM List Detail pattern

2 minute read

code

ListDetail
https://github.com/mikihiro-t/MVVMPattern

Until now, I wrote List and Detail each time by trial and error, so I tried to summarize them in a pattern.

Development environment

Build with .NET Core 3.1 + ReactiveProperty.

ListViewModel and DetailViewModel

image.png

ListViewModel.cs


this.InfoList = this.Model.InfoList.ToReadOnlyReactiveCollection(x => new DetailViewModel(x)).AddTo(Disposable);

So, ** create each DetailViewModel corresponding to each row of the DataGrid **.
When I first started learning MVVM, I didn’t know how to do this with DataGrid or ListView.

Show
The XAML for the Show button is:
Command calls the DataContext of the DataGrid, that is, the ButtonShow of the DataContext (= ListViewModel) of the Window.
The parameter becomes the DetailViewModel on this line by CommandParameter = "{Binding}" .

ListView.xaml


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

ListViewModel.cs


public ReactiveCommand<DetailViewModel> ButtonShow { get; } = new ReactiveCommand<DetailViewModel>();

** Receive the DetailViewModel itself in that line as a parameter ** (where x is the parameter)

ListViewModel.cs


ButtonShow.Subscribe(x => ShowDetail(x)).AddTo(Disposable);

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

Pass the Model (infoVM.Model) held by the DetailViewModel to the ListManager to display the Detail.

Therefore, the Model refers to the same thing in both the Row and Detail of the DataGrid, but the VMs are different.

image.png

If you want to display Detail using the same DetailViewModel used in the row of DataGrid,

ListViewModel.cs


private void ShowDetail(DetailViewModel infoVM)

At the stage of, you may use infoVM to display DetailView from ListViewModel.cs. Then the row in the DataGrid and the DataContext in the newly displayed DetailView will use the same DetailViewModel.

Remove
It’s almost the same as Show.

new order

New in the order of Model → ViewModel → View.

Main.cs


var list = new ListManager();
ViewController.ShowListView(list);

I decided to handle the new of View and ViewModel in the public static class of ViewController.

ViewController.cs


public static void ShowListView(ListManager model)
{
    var viewModel = new ListViewModel(model);
    var view = new ListView(viewModel);
    view.Show();
}

There is also a method of View → ViewModel → Model, but here Model comes first.
If the Model is running in the background and you want to display the View under certain conditions, you will have to put the Model first, and it is hard to think that there is no Model and only V and VM in MVVM, so Model first The idea is that it’s better to do new.

Dispose timing

What I don’t understand about ReactiveProperty is when to call Dispose.

DataGrid ViewModel

image.png

Clear / Remove of DataGrid is Clear or Remove of ʻObservableCollection InfoList` of` ListManager.cs`. Then, ** `ReadOnlyReactiveCollection InfoList` ** of` ListViewModel` is changed. In this code, the `DetailViewModel` was also` Dispose` immediately, so I'm not explicitly calling the `Dispose` of the` DetailViewModel` here. (I'm not sure if this is okay.)

Detail ViewModel

image.png

When DetailView is Close, it is not known whether it will be Dispose, so it is ** explicitly Dipose **.

DetailViewModel.cs


private void Close()
{
    CloseAction();
    Dispose();
}

Impressions

The flow of processing is not clear, and unless you follow it while debugging, you can not understand it just by looking at the code. I think this is the difficult part of MVVM.
However, if you pattern it, it will be a little easier to get an idea of the processing flow.

MVVM article