C# – Hierarchical View/ViewModel/Presenters in MVPVM

cmvpmvvmnetwpf

I've been working with MVVM for a while, but I've recently started using MVPVM and I want to know how to create hierarchial View/ViewModel/Presenter app using this pattern.

In MVVM I would typically build my application using a hierarchy of Views and corresponding ViewModels e.g. I might define 3 views as follows:

View A

The View Models for these views would be as follows:

public class AViewModel
{
    public string Text
    {
        get { return "This is A!"; }
    }

    public object Child1 { get; set; }    
    public object Child2 { get; set; }
}

public class BViewModel
{
    public string Text
    {
        get { return "This is B!"; }
    }
}

public class CViewModel
{
    public string Text
    {
        get { return "This is C!"; }
    }
}

In would then have some data templates to say that BViewModel and CViewModel should be presented using View B and View C:

<DataTemplate DataType="{StaticResource local:BViewModel}">
    <local:BView/>
</DataTemplate>
<DataTemplate DataType="{StaticResource local:CViewModel}">
    <local:CView/>
</DataTemplate>

The final step would be to put some code in AViewModel that would assign values to Child1 and Child2:

public AViewModel()
{
    this.Child1 = new AViewModel();
    this.Child2 = new BViewModel();
}

The result of all this would be a screen that looks something like:

enter image description here

Doing this in MVPVM would be fairly simple – simply moving the code in AViewModel's constructor to APresenter:

public class APresenter 
{
    ....
    public void WireUp()
    {
        ViewModel.Child1 = new BViewModel();
        ViewModel.Child2 = new CViewModel();
     } 
}

But If I want to have business logic for BViewModel and CViewModel I would need to have a BPresenter and a CPresenter – the problem is, Im not sure where the best place to put these are.

I could store references to the presenter for AViewModel.Child1 and AViewModel.Child2 in APresenter i.e.:

public class APresenter : IPresenter
{
    private IPresenter child1Presenter;
    private IPresenter child2Presenter;

    public void WireUp()
    {
        child1Presenter = new BPresenter();
        child1Presenter.WireUp();
        child2Presenter = new CPresenter();
        child2Presenter.WireUp();

        ViewModel.Child1 = child1Presenter.ViewModel;
        ViewModel.Child2 = child2Presenter.ViewModel;
    }
}

But this solution seems inelegant compared to the MVVM approach. I have to keep track of both the presenter and the view model and ensure they stay in sync. If, for example, I wanted a button on View A, which, when clicked swapped the View's in Child1 and Child2, I might have a command that did the following:

var temp = ViewModel.Child1;
ViewModel.Child1 = ViewModel.Child2;
ViewModel.Child2 = temp;

This would work as far as swapping the view's on screen (assuming the correct Property Change notification code is in place), but now my APresenter.child1Presenter is pointing to the presenter for AViewModel.Child2, and APresenter.child2Presenter is pointing to the presenter for AViewModel.Child1. If something accesses APresenter.child1Presenter, any changes will actually happen to AViewModel.Child2. I can imagine this leading to all sorts of debugging fun.

I know that I may be misunderstanding the pattern, and if this is the case a clarification of what Im doing wrong would be appreciated.

EDIT – this question is about WPF and the MVPVM design pattern, not ASP.NET and MVP.

Best Answer

So I think you have some minor violation of MVVM | MVPVM patterns due to linkage you're creating between the views. Neither pattern is all that verbose with respect to child windows though, so it's a bit of a murky area.

I think it's worth pointing out that the big advantage of MVPVM vs. MVVM is because of separating out business logic. The VM becomes a data container and the P handles logic plus DAL access. Bill Kratochvil's article on MVPVM was a very good read.

Bill makes a comment regarding child windows and re-use that I think is apt:
In cases where a Presenter can be reused across enterprise applications, it’s likely a module would be better suited for the task—that is, you could create a login module (project) that could be reused by all of your enterprise applications.

Which kind of reinforces that you're in murky territory with two child components.

Regardless of MVVM or MVPVM, I think you would need either

  • B-VM and C-VM when using MVVM
  • B-P and C-P and B-VM and C-VM when using MVPVM

because they are functionally separate from A. If they're not functionally separate, then why do they need their own Views?

I think the challenges you bring up with swapping ViewB and ViewC is because there is some blurring between object ownership and responsibilities. Which is really just another way of asking if B and C are functionally separate from A or not. If they are, then make them that way and if not, then don't set them up as independent.

For lightweight stuff without a lot of business logic that could be re-used, I think that MVPVM is more effort than it's worth with MVVM. That's clearly a generality, and the business logic of your application may lend itself to being expressed more elegantly with MVPVM. Based upon your question though, it sounds like MVVM may be sufficient for what you need.

Related Topic