Still trying to find good example of the more complex MVVM scenarios...
Suppose I have one viewmodel - PlayersViewModel that has a collection of Players. In one view I see the collection of Players and add/edit/delete.
Another view is teams, where I assign Players to Teams. So I have another viewmodel - TeamsViewModel. This view also needs a collection of Players. How do I keep the two player lists in sync so changes are shown in both views?
I see a number of options:
Add a reference to PlayersViewModel to my Team view (as well as a reference to TeamsViewModel) and use the PlayersViewModel.Players collection in both views
Have two different collections that reference the same underlying collection instance (somehow)
Create a static property on the Player model like Player.All that returns the collection and the viewmodels manage Players by Player.Add(player), Player.Delete, etc. instead of PlayersViewModel.AddPlayer(player)?
I tend towards #1 at the moment and using app-wide resources so the Team view can call both viewmodels. But then how do I use the selected Players in my PlayersViewModel.Players collection in my TeamsViewModel to add them?
Help please!!
My hard and fast rule is one ViewModel per View, so in my book you are on the right path. Don't confuse the PlayersViewModel with the Players data: the PlayersViewModel is oriented toward the Players View, NOT the Players data. In other words, the two are separate, so you do not need to reuse the PlayersViewModel in other ViewModels. I apologize if I'm not explaining this well...
If you need multiple ViewModels to display with the same instance of the data, then define the data at the App level rather than the Document level. You could make Players Static or you could have it implement the Singleton pattern: none of those things are specific to the ViewModel because the ViewModel merely consumes the resource.
Use a single ViewModel. Let different views display only what they need. With regard to the collection of players: WPF allows you to have multiple views of the same collection and each with a different filtering/sorting/grouping. See Binding to Collections.
Personnally, in order to be easier to understand, I have one viewmodel per view.
This means each custom UserControl has its own ViewModel, dealing with its own actions.
I'm working on a pretty big project with plenty of views, I think it is way cleaner to have one ViewModel per view. It helps me reading my architecture correctly, and therefore I won't mix roles in a unique ViewModel.
However, I cannot ensure you that's the best way to do. I started working in WPF/MVVM 2 weeks ago, I just figured out that it'd be easier to understand with this way (I am used to split my programs into as many classes as possible since I think it's easier to maintain)
Related
I always find it tempting to put a model and a view-model together in one class, and I don't see the downside of doing that.
There must be a good reason for separating them. What am I missing?
ViewModel is the soft-copy of the View i.e. if you have a updateable ListBox on View, you will have an ObservableCollection in your ViewModel that represents that list of items in the listbox. Similarly if you have a Button on your View, the VM will hold its Command.
Model will be actually what has the data that the View shows. So the type collection in your VM is of, can be termed as a Model class.
E.g. a Employees ListView is a View, and has a data context which is the instance of EmployeeViewModel class that has an ObservableCollection property of Employee class where Employee class becomes a Model.
Usually there is 1-1 relationship between View and VM and 1-N relationship between VM and Model.
The model is the domain of your application and so contains your domain logic such as business rules and validations. The ViewModel is the model for your view. It handles the interactions between the user and the view, i.e. when the user clicks a button the view model will handle that interaction and may or may not make changes to the model. Normally in an OO language, you want your objects to have a single responsibility only.
In WPF the ViewModel usually implements the INotifyPropertyChange interface which is then observed by the view for any changes. You wouldn't want the model to implement this interface since it is not related to your domain in anyway.
Another reason for separation is that sometimes your view might not necessary show all data that is in the model. For example, if your model exposes 15 properties but in one of your view the user needs to see only 5 of those properties. If you place your model in the ViewModel the view would be exposed to all 15 properties whereas if you encapsulate the model in the ViewModel then only those 5 properties would be exposed to the View.
There are probably many more reasons but in general it is a good design principle to keep them separated. With that being said, if your application is small enough you can get get away with having your model and ViewModel together to reduce redundancy in your code.
The first real downside of doing this is a lack of separation of concerns. And soon this will lead to redundant code. Now, that said, I've seen a lot times where developers have used their Model objects as ViewModels. And if we're totally honest with ourselves, in a very thin app, separating these concepts can actually lead to more redundancy.
The best thing you can do is learn more about MVVM, and its roots in MVC and Presentation Model, but I think it's a great thing that you're asking this question and that you're not blindly following dogma. In fact, I often don't even start with MVVM at all when I begin a small app. I'll often start with a hundred lines or so in the code-behind, proving a concept, and then start refactoring it into MVVM.
More to the point of your question, the model and view-model have - in a conceptual sense - very different purposes. The Model includes your business logic (domain logic), data model (objects, attributes and relationships), and data access layer. The ViewModel is essentially an adaptor for the Model, adapting it for the specific purposes of the View. In some cases you might have 3 different views (and view-models) for a given data model object. Each view-model would be adapting those same attributes on the model object for the specific purposes of that particular view.
My simple answer (and I don't pretend to be WPF Guru) would be that , in WPF, you'd need a VM when:
1. You don't want to expose all your Model to a specific view
2. Your model is not in "WPF style" (doesn't implement INotifyPropertyChanged, no observable collections or no Commands).
This is based on the example from the book:
Pro WPF and Silverlight MVVM by Gary McLean Hall
where the author only insists on how to create the Model for a DB structure (and how to implement the DAL for it).
I am looking for the correct way to create the ViewModel(s).
Here is the database model and the MVVM Model- I suspect it is not quite complete, but the Product is missing the ProductCode:
My Views will be: Pages displaying / editing views for Products, Customers and Orders
I am familiar with the Models / ViewModels implementing / using the INotifyPropertyChange and ObservableCollection, no need to insist on that.
My questions:
How to create the ViewModels in such a way that they would all share the same model
How do I manage the ViewModels? Do I have one Main ViewModel which aggregates all the specific ones? This relates to ViewModel state saving and restoring.
I am particularly interested in how to deal with this: the Model for Order has a List of Products. I will also have to maintain a list of Products for my ProductsViewModel which supports the displaying / editing Views for the Products. How can all be synchronized? Should the OrderModel only have a List of ProductCodes instead? What are the implications in that case?
In general, the thing I am after here is: how to create and manage the ViewModels for Models which implement DB tables with many to many relationships (like Product-Orders). Do we use only the foreign keys as part of the Model objects or do we use a reference to a whole other Model object represented by that foreign key?
To me it sounds like you are thinking about it the wrong way round. When you ask "How to create and manage the ViewModels for the Models which implement DB tables with many to many relationships" it sounds like you are thinking about ViewModels in terms of Models. Which isn't right. A ViewModel is a model of a View - not the Model. You shouldn't be thinking about creating ViewModels for your models, you should be thinking about creating VewModels of your Views.
In fact the model doesn't even come into it until the end. Start with your UI - your View. You then create a logical representation of that View in code so that you can bind to it, your ViewModel. Then finally you implement your ViewModel by accessing your Model to do what ever needs to be done. When you come to design the next View, even though it might contain some of the same data as the first, you would still create a new model for it - another ViewModel. Now the new ViewModel could include some of the same properties at the first ViewModel, which is fine. Remember is is a model of the View not the Model.
Consider an email app, with 2 views, summary and detail. Because there are 2 different Views you have 2 different ViewModels even though the are both pulling data from the same underlying model.
Model SummaryViewModel DetailsViewModel
----- --------------- ----------------
RecipientAddress RecipientAddress
SenderAddress SenderAddress SenderAddress
Subject Subject Subject
Content Content
Now the Summary View is only a summary and doesn't display the RecipientAddress or the Content so consequently those properties don't exist on the SummaryViewModel. The Details View displays more information, so has more properties. This same idea answers your question about foreign keys. Foreign keys are never visible on your View therefore have no business being members of your ViewModel. Your ViewModel cares only about what is required for the View.
In answer to your question "how do you manage the view models": you don't. You don't have to. ViewModel instances usually (not not always) have a one to one relationship with the Views, therefore you don't need to manage them. They only live as long as the view lives. You just create a new instance of the ViewModel when the View is loaded (typically in OnNavigatedTo event handler, see below) and store it in the View's DataContext. If two instances of the View are loaded, then there are two ViewModels. When the View is GC'ed, the ViewModel is too (if it isn't you have a memory leak).
Finally, as for how you should synchronize changes, that can be tricky in a desktop Silverlight app where many views might display concurrently. Fortunately on the Windows Phone we usually only have one view open at a time (although not always). So we can simply tell our ViewModel to refresh each time the page is navigated to:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (DataContext == null)
DataContent = new MyViewModel(); //Create new instance of the ViewModel
else
(MyViewModel)DataContext.Refresh(); //Refresh the existing ViewModel
}
This works well in most cases for more advanced scenarios you could look at the messaging infrasructure provided by a toolkit like Prism or MvvmLight.
Hope this has helped.
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 (i.e., 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.
I just need a simple clarification:
I have an example application with a Model of a ball, and two views (lets say one shows the ball and lets you resize if with the mouse, change it's colour with a click, the second has a control with two child controls (size textbox and colour picker)).
Does MVVM say I must have two VM here, one for each specific View, or am I allowed to reuse the VM without breaking the pattern?
As a follow up question, if I am required to have two VM's is it legitimate, according to the pattern to have one as a derived type of the other, or both as derived types of a base class, or composite classes based on common parts? Basically fulfilling the need for two types but improving reuse?
My example is contrived, I've tried to make the point that both Views affect the same two properties of the model. Max size, available colours, etc are the same between both views.
Thanks
Use the same coding practices in MVVM that you use anywhere else. In particular, stay DRY. So if you can use the same view model, then do so. I would say reuse of a view model is extremely rare though. If you later have to refactor into two separate view models but can derive from a common base class to reuse common parts, etc. then do so.
Yes, VM is very specific to a view and likelihood of re-using is very slim.
In fact I would go further, if you can re-use a VM then I would say it is most probably duplication of the view.
The only exception I can think of is the child view in a nested hierarchical object model structure.
It is entirely appropriate to share ViewModels in this situation. A ViewModel is the glue that allows a View to create a representation of a Model. If you have two Views that represent the same aspects of the Model, it is logical to use the same ViewModel.
If you find over time that the Views are different representations of the Model, then you need to revisit the design.
Although not directly answering your question, check out this insightful post from Josh Smith regarding the re-use of ViewModels and the "friction" caused from sharing: http://groups.google.com/group/wpf-disciples/msg/c29b3935ec9d3c4e
He is basically proposing an improvement to MVVM (calling it MMVVVM; phew!) - the extra MV is for ModelView. As the others have mentioned, the ViewModel is specific to a View and re-using that is not very likely. But rather, create a wrapper around the Model (the ModelView), which can be re-used with any ViewModel.
We had a case some time ago where we needed a view duplicated in several places, but the underlying types of the views and viewmodels were different. In that case, we created a generic viewmodel and passed in the underlying types as parameters when constructing the viewmodels and were able to avoid code duplication that way. As the others say, this situation is rare so most times you'll be creating new viewmodels (although all viewmodels will probably inherit from a common base class for e.g. property notification.)
We also tend to create POCOs from our database entities so that our database context isn't changed until we really want to apply changes (i.e. the MMVVVM(!) pattern that Chris described)
Whilst implementing my first MVVM application in WPF, I've been wondering about the pros and cons of wrapping Model collections in related ViewModel collections to use in the View.
In our system we are likely to have several potentially large collections e.g. Order Lines in an Order, and Stock Items which could be selected for an Order Line. At present these are looked up from SQL in the Data Access layer, and then SqlDataReaders are looped around to create a collection of Model Objects.
To then loop around the collection of Model objects when creating a collection of ViewModel objects seems like an unnecessary overhead. When there are large collections of Model objects would it be better to expose these directly on the View?
Thanks in advance for your help, Mark
Edit
While reading up on this subject I found this MSDN article from July this year (reviewed by Josh Smith no less) which gives a pretty balanced view of MVVM, and in the 'Collections' section said this:
Another problem with collections is
determining when or if to wrap each
Model instance in the collection
within a ViewModel instance. For
smaller collections, the ViewModel may
expose a new observable collection and
copy everything in the underlying
Model collection into the ViewModel
observable collection, wrapping each
Model item in the collection in a
corresponding ViewModel instance as it
goes. The ViewModel might need to
listen for collection-changed events
to transmit user changes back to the
underlying Model.
However, for very large collections
that will be exposed in some form of
virtualizing panel, the easiest and
most pragmatic approach is just to
expose the Model objects directly.
Thanks very much for the comments so far, trying to limit the amount of data passed into the ViewModel, or using paginated or other suitable controls would reduce problems I'm sure, but I wonder if there would there still be situations where it would be better to simply bind to a collection of Model objects within the ViewModel?
I guess that it would really depend on how you want to go about displaying the data. Afterall the ViewModel is primarily there to handle the data that the View requires.
Assuming that your data layer provides you with just the data collections you could always restrict the creation of elements within the ViewModel depending on those that you actually want to see.
For example you may have a Datagrid to display Order Items for a given Order.
Thus you could have a ViewModel Property AllOrderItems bound to the datagrid and yet its getter is as follows:
public List<OrderItems> AllOrderItems
{
get{return this.DataAccessLayer.GetOrderItems().Where(x=>x.OrderNumber==this.OrderNumber).toList();
}
Here the DataAccessLayer is a class that holds cache database data and interfaces to the database. If kept as a singleton then data duplication within it will be reduced.
You can adapt your ViewModel to do as much or as little filtering of data from the DataAccessLayer as requried. The collections can be Observable if requried and the DataAccessLayer can generate events for VMs to react to for cases of new data being added, removed, saved to the database.