Model-View-ViewModel
- Hello,
I want to build a bigger application with WPF and it should have a structure like MVC. I heard about the Model-View-ViewModel Pattern but I have never seen an example of how a ViewModel looks like.
I don't want to have all that event-code in my code-behind file and thats why I am thinking of the ViewModel Pattern. I want to be able to seperate my business logic from the ui.
Any suggestions or hints?
Thanks
Answers
To start with, I notice your model does not expose any change notifications. This is the classic case where the wrong thing to do is write some tangled code in your UI that updates the Model and tells other parts of the UI what it did. In classic MVC you would have to write code that implemented the Observer pattern yourself, and view code that reacts to the change notifications, updates selection and pushes changes back to the Model. But WPF data-binding can do all that plumbing for you, if you have the right things for it to hook on to. You need to wrap your Model with something appropriate for data-binding: your ViewModel.
For lack of a better name, call it FinancialInformationViewModel. Here's an example:
public
class FinancialInformationViewModel{
private FinancialInformation model;
private ListCollectionView accountsView; public FinancialInformationViewModel(FinancialInformation model)
{
this.model = model;
this.accountsView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.model.Accounts);
} public ListCollectionView Accounts { get { return this.accountsView; } }
}
Or if it were a pre-existing web service it might have already have events like "AccountAdded" and "AccountRemoved" on FinancialInformation. In that case you would also write a FinancialInformationViewModel wrapper, that wrapper would hook the Added/Removed/Changed events on the Model and re-fire through INotify...Changed.I imagine you want to do a Master-Detail type UI with a list of accounts and when you select an account, show a list of Transactions. You need DataTemplates for Transaction and Account. You set the DataContext of your form to an instance of FinancialInformationViewModel, add a couple of list boxes, the first one has ItemsSource={Binding Path=Accounts} (and don't forget IsSynchronizedWithCurrentItem="true"). The second list would have ItemsSource={Binding Path=Accounts/Transactions}. The data-binding engine manages selection changes for you automagically...no view code need apply. You could also expose ICommands off FinancialInformationViewModel and bind buttons like "Load" and "Save" to those commands. Just to give further flavor, you might want to display the Amount in different currencies. In that case you would write seperate DataTemplates (or ValueConverters to and from string), and use a PropertyTrigger off FinancialInformationViewModel.CurrencyType to switch them around...
Whatever the details, like you suggest, I'm fussy about adding INotifyPropertyChanged and INotifyCollection changed directly to my model. They are defined in WindowsBase, which is supposed to be stuff that is usable across WinFX, not just WPF...but it would restrict your portability for awhile and if at somepoint you have to deal with another UI or data framework that has its own way of doing this...then you'd have multiple ways implemented on your model.
Hope this helps.
- I'm not absolutely sure what the scenario is still, so I'll proceed cautiously, and at least perhaps something I say will clarify something. Who is changing the Accounts list? Is the database automatically updating it in the background? Or is it simply through the UI? If the database is changing the model, then you've got to have that update process fire some kind of changed events. In that case you probably need to sub-class ListCollectionView, have it listen for "AccountsAdded" and call its protected OnCollectionChanged() method to trigger the right notifications. If your Model is changing and not telling anybody...well then you have to change the Model.
If you have Commands working against the Accounts list, you should wrap Accounts in an ObservableCollection too. Putting it all together, if the UI is changing the Model and it is being updated behind the scenes, the worst case is:
public
class FinancialInformationViewModel
{
private FinancialInformation model;
private ObservableCollection<Accounts> accounts;
private ListCollectionView accountsView;
public FinancialInformationViewModel(FinancialInformation model)
{
this.model = model;
this.accounts = new ObservableCollection<Accounts>(this.model.Accounts);
this.accountsView = new AccountCollectionView(this.accounts);
} public Collection<Accounts> Accounts { get { return this.accounts; } }
public ListCollectionView AccountsView { get { return this.accountsView; } }}
class
AccountCollectionView : ListCollectionView
{
public AccountCollectionView(FinancialInformation model) : base(model.Accounts)
{
this.models.AccountAdded += this.AccountAdded_Handler;
...
}
void AccountAdded_Handler(AccountChangedArgs e)
{
this.OnCollectionChanged(...);
}
}
All Replies
- John Gossman's Blog is probably your best bet.
- As I re-read your post it appears to me that you've probably already looked at Gossman's blog. I am also trying to build a somewhat smaller application and want to try out the Model-View-ViewModel pattern.
Here's my problem. I have several business classes which contain many different properties and generic lists. Traditionally I have just been storing an instance of the base class (which has references to all the other classes) as the DataContext of the Window. I then use WPF's binding to get the information I need in different controls. This is simple Model-View.
The problem arrises when WPF suggests or requires that I annotate my classes with WPF specific constructs, such as the INotifiyPropertyChanged interface and the idea of DependencyProperties. This directly goes against the idea of separating business logic from UI, because already I'm limiting my business classes to a machine that has WPF installed (wheras, I might want to port over that business code to another platform and simply remake the UI).
Is this where the ViewModel comes into play? Is the ViewModel a structure that helps communicate the vanilla business structures and the annotated View requirements? - The ViewModel is a model of the view. That means: You want to DataBind a property from your DataObject (model) to a property from your ViewObject (view) but you sometimes cannot bind directly to a CLR property of the model (because of converting or calculating). This is when ViewModel comes into play. It propagates the already calculated or converted value from your model, so you can bind this property directly to the view property.
Im am thinking about to have a ViewModel which has references to all my model classes. The ViewModel can be accesed with the singleton pattern in a static way.
I dont see that implementing the INotifiyPropertyChanged interface goes against seperating the ui from the model if you stay in WPF. So your Model is depending on the WPF Plattform. DataBinding is a helpful feature of WPF. If you want your model to be independed you have to think about a traditional way to keep your UI updated. Thomas Barmeyer wrote: The ViewModel is a model of the view. That means: You want to DataBind a property from your DataObject (model) to a property from your ViewObject (view) but you sometimes cannot bind directly to a CLR property of the model (because of converting or calculating). This is when ViewModel comes into play. It propagates the already calculated or converted value from your model, so you can bind this property directly to the view property.
Im am thinking about to have a ViewModel which has references to all my model classes. The ViewModel can be accesed with the singleton pattern in a static way.
I dont see that implementing the INotifiyPropertyChanged interface goes against seperating the ui from the model if you stay in WPF. So your Model is depending on the WPF Plattform. DataBinding is a helpful feature of WPF. If you want your model to be independed you have to think about a traditional way to keep your UI updated.
The reason I don't like implementing INotifyPropertyChanged is because according to the Model-View-ViewModel pattern, the business logic should be entirely separated from any UI logic. INotifyPropertyChanged seems to be UI logic.
By the way, I also found this great feed from the PDC which should clear up any confusion about MVVM.
http://microsoft.sitestream.com/PDC05/TLN/TLNL03_files/Default.htm#nopreload=1&autostart=1- INotifyPropertyChanged is the interface that forces my class to fire the PropertyChangedEvent if data changes. The View or Binding object acts as a listener and in the event handling method pulls for the data.
I've also seen the session from the PDC but I have never seen some sample code of an implemented ViewModel...
I am quiet sure that the guys from the sparkle team have used the INotifyPropertyChanged in there Model?!
greetings from Germany - Yes, the ViewModel implements INotifyPropertyChanged on behalf of the Model if we do not want to or do not have the option (the Model is pre-existing or can't take such a dependency). ObservableCollection in WPF is an example of such a ViewModel that wraps the underlying Model.
Generally, a ViewModel is as much conceptual as code...so it may consist of one or more classes or even just a method or interface on another class.
My apologies for not finishing my series on M-V-VM on my blog...major deadline for the end of the year. Christmas break project is to do an example... Please post questions to my blog, here or directly e-mail if you want interim guidance. - In short, "Yes" this is one of the places the ViewModel comes into place. It adapts the Model to the UI technology (data-binding, specific interfaces, type converters) and provides view state (selection etc.). Note it does not have to be a single class...you may implement the view state as one class, the WPF specific bits as another etc. The ViewModel is very much conceptual rather than a strict way of writing classes.
Hope this helps,
John Gossman - John, I was wondering if you could help me decypher what I should do in a situation such as this.
Let's say I have a pre-existing model. In reality, I'm building this model alongside the view, but I want to allow it to be ported to other platforms (my Smartphone perhaps?). Anyway, here's what the class structure looks like:
public class FinancialInformation
{
private List<Account> _Accounts;
public List<Account> Accounts { /* get and set methods */ }
}
public class Account
{
private string _Name;
private List<Transaction> _Transactions;
/* and their respective properties */
}
public class Transaction
{
private string _Description;
private decimal _Amount;
/* blah blah blah */
}
public static class FIFactory
{
public static FinancialInformation get(Stream stream)
{
/* blah blah blah */
}
}
Anyway, as you can see this structure can easily be ported over to the compact framework (does CF 2.0 support static classes?). However, if I was building a XAML UI around this model, I might want these classes to implement INotifyPropertyChanged or change from List<T> to ObservableCollection<T>. What would I do in this case? You can make use of a class that works for databinging on lists in every version (.NET CF 2.0, .NET 2.0 and Avalon). It's BindingList<T> - I have used in one of my projects, I was able to use the same model in both .NET 2.0 and Avalon (and I intend to use it in .NET CF 2.0 too).
And by the way, INotifyPropertyChanged and static classes are supported in .NET CF 2.0.
Regards,
Valentin Iliescu- Does BindingList<T> notify an Avalon application when changes are made to any of it's items?
I suppose this is ok because those classes are available in the BCL and CF's BCL, but it still seems to be mixing UI in business logic.
Care to share what you would suggest we do in this case to achieve best MVVM programming practices Mr. Gossman? To start with, I notice your model does not expose any change notifications. This is the classic case where the wrong thing to do is write some tangled code in your UI that updates the Model and tells other parts of the UI what it did. In classic MVC you would have to write code that implemented the Observer pattern yourself, and view code that reacts to the change notifications, updates selection and pushes changes back to the Model. But WPF data-binding can do all that plumbing for you, if you have the right things for it to hook on to. You need to wrap your Model with something appropriate for data-binding: your ViewModel.
For lack of a better name, call it FinancialInformationViewModel. Here's an example:
public
class FinancialInformationViewModel{
private FinancialInformation model;
private ListCollectionView accountsView; public FinancialInformationViewModel(FinancialInformation model)
{
this.model = model;
this.accountsView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.model.Accounts);
} public ListCollectionView Accounts { get { return this.accountsView; } }
}
Or if it were a pre-existing web service it might have already have events like "AccountAdded" and "AccountRemoved" on FinancialInformation. In that case you would also write a FinancialInformationViewModel wrapper, that wrapper would hook the Added/Removed/Changed events on the Model and re-fire through INotify...Changed.I imagine you want to do a Master-Detail type UI with a list of accounts and when you select an account, show a list of Transactions. You need DataTemplates for Transaction and Account. You set the DataContext of your form to an instance of FinancialInformationViewModel, add a couple of list boxes, the first one has ItemsSource={Binding Path=Accounts} (and don't forget IsSynchronizedWithCurrentItem="true"). The second list would have ItemsSource={Binding Path=Accounts/Transactions}. The data-binding engine manages selection changes for you automagically...no view code need apply. You could also expose ICommands off FinancialInformationViewModel and bind buttons like "Load" and "Save" to those commands. Just to give further flavor, you might want to display the Amount in different currencies. In that case you would write seperate DataTemplates (or ValueConverters to and from string), and use a PropertyTrigger off FinancialInformationViewModel.CurrencyType to switch them around...
Whatever the details, like you suggest, I'm fussy about adding INotifyPropertyChanged and INotifyCollection changed directly to my model. They are defined in WindowsBase, which is supposed to be stuff that is usable across WinFX, not just WPF...but it would restrict your portability for awhile and if at somepoint you have to deal with another UI or data framework that has its own way of doing this...then you'd have multiple ways implemented on your model.
Hope this helps.
- Great explanation John. I was already setting the DataContext of the root NavigationApplication to an instance of FinancialInformation, and using relative binding on two ListViews. I just needed a way to respond to the model changing (e.g. another thread queries my bank and gets a new set of transactions) without a lot of plumbing code. I'm going to try this out.
Thanks again. - Now that I've had time to try it, I still don't see how it helps me solve my syncronization problem (maybe I'm just missing it).
As I understand it, the ListCollectionView holds information about the current state of a view of the list. For example, which one is selected, what kind of sort it has, etc.. However, it doesn't help me detect and respond to changes in the underlying list. The ListCollectionView only has events for when the current selected item is changing.
How would I, in the example you gave above, detect and respond to a new instance of the Account class being added to the Accounts list?
Thanks! - I'm not absolutely sure what the scenario is still, so I'll proceed cautiously, and at least perhaps something I say will clarify something. Who is changing the Accounts list? Is the database automatically updating it in the background? Or is it simply through the UI? If the database is changing the model, then you've got to have that update process fire some kind of changed events. In that case you probably need to sub-class ListCollectionView, have it listen for "AccountsAdded" and call its protected OnCollectionChanged() method to trigger the right notifications. If your Model is changing and not telling anybody...well then you have to change the Model.
If you have Commands working against the Accounts list, you should wrap Accounts in an ObservableCollection too. Putting it all together, if the UI is changing the Model and it is being updated behind the scenes, the worst case is:
public
class FinancialInformationViewModel
{
private FinancialInformation model;
private ObservableCollection<Accounts> accounts;
private ListCollectionView accountsView;
public FinancialInformationViewModel(FinancialInformation model)
{
this.model = model;
this.accounts = new ObservableCollection<Accounts>(this.model.Accounts);
this.accountsView = new AccountCollectionView(this.accounts);
} public Collection<Accounts> Accounts { get { return this.accounts; } }
public ListCollectionView AccountsView { get { return this.accountsView; } }}
class
AccountCollectionView : ListCollectionView
{
public AccountCollectionView(FinancialInformation model) : base(model.Accounts)
{
this.models.AccountAdded += this.AccountAdded_Handler;
...
}
void AccountAdded_Handler(AccountChangedArgs e)
{
this.OnCollectionChanged(...);
}
}


