简体   繁体   中英

One Model Entity, Multiple Pages -> Multiple Views? Multiple ViewModels?

Due to limited screen real estate I will be capturing user input for a single entity using multiple pages (displayed consecutively - think wizard). In my model I expect it is correct to model this entity as a single class.

In an MVVM implementation I am assuming it is best MVVM practice to consider each page as a seperate View. Is this correct?

Is there a consensus on the best MVVM practice for whether each Page has it's own ViewModel or should there be one ViewModel instance that is referenced by the multiple Pages?

To illustrate:

Option 1

Class A (X, Y, Z)
ViewModelA1 (X)
ViewModelA2 (Y)
ViewModelA3 (Z)
View1 captures ViewModelA1
View2 captures ViewModelA2
View3 captures ViewModelA3

Option 2

Class A (X, Y, Z)
ViewModelA (X, Y, Z)
View1 captures ViewModelA.X
View2 captures ViewModelA.Y
View3 captures ViewModelA.Z

The word "View" says it all. It's a view of the data. The ViewModel's job is to make the data coming from the model presentable. Whatever needs to be done to the data happens in the viewmodel so that the view can show it.

Normally you will have a one to one relationship of you view to viewmodels, because normally you only want to show that data in one way. (one "view") Where I deviate from the normal practice (possibly from MVP pattern?) is that if you want to show the data in a number of different ways (for example you want a bar graph or a line graph, or a pie chart) and the data is the same for all of the views then you only need one viewmodel. Its a case of the DRY principle. If you have three viewmodels and they are all the same, then use one viewmodel. Multiple Views. One viewmodel.

I'm sure there are folks that would argue strongly one way or the other. From my perspective, it all depends on what code you need to re-use. There are both View-centric and Model-centric ways of constructing your ViewModels, and I don't think that either one is always going to be the right approach.

If you find that your ViewModels tend to be heavy on UI-specific logic, a good design will tend towards a 1:1 relationship between Views and ViewModels, with each ViewModel wrapping multiple Models. The danger in this approach is that you can spend a lot of code wiring up the data in each ViewModel and keeping it in sync, and this wiring would need to be repeated across each ViewModel. Uggh.

However, you may also have a situation (as I do in my current project) where the ViewModels have to cope with complex relationships in the underlying model, and where the various Model entities can be updated from multiple endpoints (ie, either the user or a duplex WCF service). When this is the case, you spend a lot of time in each ViewModel making sure that its data is in sync with the underlying models, and it would be silly to re-do all that logic in each ViewModel. In this scenario, I've found that the cleanest approach is for your ViewModels to map more-or-less 1:1 with models, and to be re-used across multiple views. The downside to this approach is that you can end up with a lot of UI-specific code from various different Views mixed into the same class, and that can make it hard to test and maintain. (Yes, I know that ViewModels are supposed to not be tightly coupled with any specific UI, but you still end up with a lot of code that says, in effect, "When the user executes this command bound to some UI element that I'm pretending not to know anything about, do this other thing that I'm pretending I don't know is going to result in a dialog box being raised." Even at that level of abstraction, the logic coded into the ViewModel can vary from View to View.)

Then there are various hybrid approaches, which are likely the most helpful in real-world scenarios. For instance, you might end up employing an inheritance hierarchy within your viewmodels, so that you deal with the generic wiring in one or more base classes, and then add in the UI-specific pieces in the classes further down the inheritance chain.

For what it's worth, one of my frustrations with most MVVM articles and what-not is that they deal with excessively simplistic scenarios that don't reflect the complexity you find in the real world. As soon as you get past a Customer -> Order -> OrderDetail sort of form, I've found that most of the recommendations I've read tend to breakdown, and I'm left finding my way on my own.

Relevant best practices, regarding MVVM, as I was taught (and practice):

  • Each page/View has a single ViewModel.

  • The ViewModel should only have fields/properties relevant to the View that uses them.

  • ViewModels can be combined from multiple underlying logical Models/classes as appropriate.

The above can end up with more models but they are easier to work with over time as the changes to a single View/ViewModel don't impact other Views or ViewModels

This matches your first option .

In an MVVM implementation I am assuming it is best MVVM practice to consider each page as a seperate View. Is this correct?

Yes, I would do so depending how complex is it. I think that MVVM for most of the WP7 apps is just an overkill.

Option 1 is the better model to use.

I am not sure what you mean with the X, Y and Z.

You should simply pass the same instance of the model to each ViewModel

Class Model
{
  string X { get;set;}
  string Y { get;set;}
  int Z { get;set;}
}

Class MainViewModel
{
  // constructor
  ViewModel()
  {
    model = new Model()
    SubViewModel = new SubViewModel(model);
  }

  Model model {get;set;}
  SubViewModel sub { get;set;}

}

Class SubViewModel
{
  // ctor
  SubViewModel(Model model)
  {
    this.model = model;
  }

  Model model { get;set;}
}

The MainViewModel handles navigation between each SubViewModel, but they are all looking at the same instance of the Model, so they all have the same data.

On some Tasks I may have multiple models associated with a single ViewModel and multiple views for that Task. For Example, Creating a product with grouping, images, etc.. Focused around the product.

I also have Tasks where multiple ViewModels are used driven by the Task through multiple Views. For Example, Creating a User account in the application with a mashup of multiple 3rd party accounts like Facebook, Twitter, etc where each 3rd party API has it's own set of requirements but appears as a single Task to the user through a series of steps. Focused around the User account.

MVVM pattern is flexible dependant on the need. Define the task, break it down, and decide on which best suits the task.

Look, what are you asking is this:
I have 1 M.
I have 3 Vs. (Assuming that it's preferable for you to create 3 Vs).

Should I have 1 VM or 3 VMs ?? In other words you ask, in which side the VM concept is closer ? On the M or the V side ?

From my experience thus far with the pattern, the VM is MUCH more closely related to the V.

So the quick answer to your question is: 3 VMs (Option1). Option 2 is the wrong way to think of this pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM