Silverlight MVVM linking model and view model - silverlight

There are lots of great examples around on MVVM but I'm still confused.
Lets say you have a CustomerModel and a CustomerViewModel. It seems there would be a Name property on the CustomerModel and one on the CustomerViewModel. The setter on the CustomerViewModel will set the CustomerModel Name property and then call the OnPropertyChanged(PropName) so that the UI will update. Is this really right? Seems like the getter/setters will be defined twice. If you have a model with 50 properties then thats going to get real tedious.
Also, lets say I set a Qty property. The ViewModel updates the Model. The Model updates its Value property based on the new Qty. How does the ViewModel get notified that the Model property changed?

Your ViewModel doesn't have to encapsulate the Model that strictly. In your scenario, the CustomerViewModel might have a Customer property, which in the end means your View binds to the Model properties... it just does so through the ViewModel. That's perfectly legitimate. That said, however, there's often a benefit to encapsulating this. Your business model may not include change notification. You may not want the user interaction to modify the business model until the user clicks an OK button. Your business model may through exceptions for bad input, while you want to use another form of validation. I'm sure you can think of other things. In fact, I'd guess that most of the time you're going to want the encapsulation, so it's not really "tedious" in the sense of just writing a lot of pointless relay methods.

In the customer example that you give, the CustomerModel contains all the information that is stored by your database (or other backend). The CustomerViewModel contains similar information if it's going to be shown on the UI (Name etc., potentially 50 other properties if you have a large class) but as uses the INotifyPropertyChanged interface to show them as properties that the View (i.e. the XAML) can bind to.
e.g.
public int Name
{
get
{
return this.name;
}
set
{
if (this.name!= value)
{
this.name= value;
this.OnPropertyChanged("Name");
}
}
}
The ViewModel also contains other bits of UI state - Visibility flags, current Tab index, more complex bits of text built out of data in several fields, ObservableCollection<> of child items, etc. All are there to be bound to the XAML.
I have seen the ViewModel created from the Model as a one-time, one-way process, e.g. with a constructor:
CustomerViewModel viewModel = new CustomerViewModel(customer);
or as an extension method
CustomerViewModel viewModel = customer.ToViewModel();
I haven't seen any provision for updating a ViewModel for changes to the Model - the point of the ViewModel is that it's isolated from the model. It keeps a separate copy of the data. It does not propagate changes back to the model, not until you press a "save" button. So if you cancel instead, nothing in the model has changed and there's nothing to undo.
You may be trying too hard to keep the ViewModel up to date with the Model - most cases like save or load you can just throw away the current ViewModel and make a new one from the current state of the model. Do you need to keep the ViewModel's UI state and change the data in it? It's not a common requirement but it could be done with a method or two called when the save or load happens.
So there's also the assumption that this wire-up logic happens somewhere. This is why most patterns that involve views also involve controllers that are responsible for acting on commands (e.g. show a customer, save a customer) and setting up new UI state afterwards.

Exactly how this is done, will depend in part on your business model as wekempf has already stated.
Depending on how your displaying Customer info in your UI, you might have an ObservableCollection of Customer(your model) types in your ViewModel. If, for example, you're displaying a master/detail scenario, where you might have a list of customers and show details below when a particular customer is selected.

Related

MVVM, collections and ORM

I was trying to use MVVM design pattern with WPF and Entity Framework to create a simple application. All goes well and good if the classes are loosely coupled, but if I have sth. like two model classes : Customer and Address and a Customer has a collection of Addresses.
Now for those classes I need to create two VM classes - CustomerVM and AddressVM. CustomerVM should have ObservableCollection of AddressVM objects. Every change made to those VM classes(which includes all CRUD operations on both CustomerVM and AddressVM) needs to be reflected in the model classes - which is why I end up writing a looot of code that eg. subscribes to the changed event of ObservableCollection and if a new object is added then add a new object to the model ... and so on ...
What to do with this? Is this usual while using MVVM? Am I doing everything ok? How to cut down the amount of code needed for such a simple class hierarchy? Are there any frameworks that can create basic VM classes that "behave well" with other classes in hierarchy? What to do if class relationships get MORE complex?
OR TO PUT IT SIMPLE:
How to reflect changes done in vm collections in model collections :
CustomerVM1.AdressesVM.Add(new AddressVM{City="New York"})
should cause an equivalent of:
Customer1.Adresses.Add(new Address{City="New York"})
There's also the same problem the other way round - how to reflect changes done to collections in model to be included in the view model, but I'm more interested in the first one, because it has a more practical application and vm objects can in most cases be simply recreated.
You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF). It shows how to use the Entity Framework and MVVM together.
Short hint: It doesn't create a wrapper ViewModel for every Entity class. Instead, it creates the ViewModel classes for the Views.
You're running into exactly the same problem I ran into when trying to figure out how to keep an ObservableCollection in my ViewModel sync'd with a plain-old-collection in my Model. An ObservableCollection is wonderful because the View can bind to it and automatically change when the collection changes. Unfortunately you've just moved the problem of sync down one level.
One option is to use ObservableCollections everywhere, even in the Model. This isn't very clean architecture because MVVM isn't supposed to make any demands on the Model.
What I did to solve it was to introduce a Presenter, so my architecture looks like this:
View -> ViewModel <-> Presenter <-> Model
Also, I made my ViewModels dumb. Here's how a typical user action takes place from initiation to completion:
User clicks the Add button
ViewModel either raises an event that the Presenter subscribes to, or calls a method on the presenter, or just calls a callback that the Presenter provided to the ViewModel when the ViewModel was constructed. Essentially it delegates the action to the Presenter.
The Presenter calls Add on the Model.
The Model reacts to the Add call, updating all of it's relevant state, including the plain-old-collection.
The presenter, having executed the action on the model, then reads the new state from the Model and writes the state into the ViewModel. Binding takes care of synchronizing the View.
So in your case, the Presenter could subscribe to a CollectionChanged event on the ObservableCollection in the ViewModel, and when it changes, it reacts to the event by calling Add on the Model. On the other hand, when the Presenter is processing some other user action that calls Add on the Model (it knows because it handles all interaction with the Model), then it knows that it has to propagate that change to the ObservableCollection in the ViewModel.
In my code, I simplified the situation... after every user action is executed on the Model by the Presenter, I do a straight copy of all relevant state in the Model to the applicable place in the ViewModel. You're doing a little more work than you need to, but in a typical CRUD type of application, there's no noticeable performance issue. If I have a really big collection of objects, performance could be a problem, and there I drop down to a more fine-grained synchronization (updating only the changed entity), at the expense of more complicated logic.

Creating a tabcontrol in MVVM from a central datasource

I am new to MVVM, and I am trying to implement a simple application, following the pattern.
For simplicity, I am breaking the problem down to it's simplest form. If I manage to get this to work, I will have little trouble getting the application made.
The simple application consists of a tabcontrol. It is important that both tabs have their own ViewModel. However, they will get most of their data from the same source. The main issue is to get the second tab to know that the first have initiated a change on the datasource.
So, for simplicity, let's just say that the model is holding a single integer. This integer needs initially to be set to 1.
The first tab is holding a textblock and a button. The text of the textblock is bound to the integer in the datamodel. Upon pressing the button, the integer in the moddel should be incremented with 1.
The second tab holds only a textblock, also bound to the integer in the datamodel. The challenge is to get this textblock to update along with the first textblock, but still being it's own viewmodel.
I need somewhere central to store the values of the model, and in some way, let the viewmodels know that they have been updated, so their properties can be updated, and the Views therefore get's updated accordingly.
Can someone explain in as much detail as possible how this is done? I have tried a billion different ways, but I am not getting it to work.
Let me see if I have your question down right:
You have a data source (your model).
You have 2 view models.
View model 1 changes data in the model.
View model 2 needs to update with changes in the model.
If that all sounds right, here's one solution:
Have your model implement INotifyPropertyChanged. When the integer changes, raise the PropertyChanged event. In view model 2, listen for the model's PropertyChanged event. When it occurs, raise view model 2's property changed event, and its UI will get updated automatically.
I have no idea in which scenario you want to do that.
But a solution that crosses my mind is to have a "parent" ViewModel that holds instances of the two tab ViewModels.
e.g.
public class ParentViewModel{
private Tab1ViewModel viewModel1;
private Tab2ViewModel viewModel2;
}
Then the ParentViewModel can subscribe to the INotifyPropertyChanged event of the ViewModel1 and set the value on the ViewModel2.
I have recently implemented something similar to this. It was for implementing a wizard, consisting of:
7 Views
8 View models
1 Model
The main ViewModel created the Model and passed this on to all the other view models through their constructors.
In your scenario you could have a main ViewModel with an ObservableCollection of ViewModels. Each of these VM's would have the same instance of the model as their data source.
As previously mentioned, implement INotifyPropertyChanged on the model and bind the views directly to the model through a property on the ViewModel. I found this diagram very useful : http://karlshifflett.files.wordpress.com/2009/01/wpflobmvvm1.png

MVVM WPF ViewModels for Adding New Entity

My concept for MVVM in WPF is that we have a ViewModel for every Model in your application. This means that if we have Customer class (entity) then we will have CustomerViewModel. The CustomerViewModel will have all the properties which are necessary to represent a customer. The CustomerView usercontrol will be responsible for creating the UI for the Customer model.
Now, let's say that we are adding a new customer. So, we have a form which consists of FirstName, LastName etc. Do we need a ViewModel for this scenario. I mean all I have to do is to take all the input values from TextBox and create a Customer object and then save it to the database. Why should I bother creating a ViewModel for this scenario?
First of all, that is not the main purpose of MVVM, to "mirror" everything. The View should provide the means for a user input, and certainly not process calls to any of the database layers. The ViewModel should be a GUI-agnostic application backbone, and it definetly should handle the creating of customers.
That said, what you should do, is have a ViewModel which represents a workspace for handling customers, and not just a customer ViewModel. If you really want to save on a few objects being created, add to that workspace the possibility to create and add a new customer (not CustomerViewModel). That way, you can have a View of the workspace which has elements for each relevant/required property of the customer, and by invoking some command added to that workspace ViewModel, you could get the current values filled in those (data bound to ViewModel) View elements directly to the customer model.
Consider if you could probably drop the specific customer (and other Model) ViewModels if you refactor things a bit, it would be good practice to keep things from adhering blindly to a certain pattern without explicit cause.
Let's pretend for a second that there is no business model. The only thing you have is a view. If you were to model just that view, without any knowledge of what the data means elsewhere in the system, that is a ViewModel.
The goal of a ViewModel is to, well, model the view it backs. This is a different goal than modeling the idea of a customer in your business domain. To say you will have have one ViewModel per business entity, then, is to say you will have one view per business entity, which leads to run-of-the-mill data-focused UI.
In your particular case, think about the customer edit view. It has fields that correspond to a customer's properties, and thus seems like a natural fit for binding to a customer directly. However, where on the customer object is the "Submit" action modeled? Where is the "Cancel" action modeled? Where is it modeled that field X is an enumerated value selected from a list?
How about the password? If persisted as a binary hashed value, does the view know how to hash its text? What if the system has password strength requirements?
The ViewModel is the mortar between the business model and the UI. It takes concerns from one and translates them into terms of the other. It is the point at which all the above issues are addressed. To say a ViewModel isn't necessary is to ignore its necessity.
You don't need to have a separate ViewModel for Add, you only need a single ViewModel which should do Edit and Add scenarios. If you can delete the record from the edit page than that ViewModel should also have the ability to delete. Your ViewModel should reflect the functionality your View exposes regardless of data.
I think you should reconsider having a single ViewModel for each model. I like to think of ViewModels as normalizing behavior inserted of data. By having a ViewModel for each Model class you will run into architecture issues sooner or later. I look at the application from top down overview, what is my UI trying to accomplish and from there I will get to the ViewModel and eventually I will get to my DataFactory and how the ViewModel maps down to data is almost always not 1 to 1 except for the most simplistic Views. If you try to map 1 to 1 you will have bad UI or your data will not be normalized very well.
The Stack we have here is:
View
ViewModel (Controls everything the user can do in the view, wraps properties from our POCO's)
DataFactory (Maps our POCO's to Entity Framework objects and CRUD)
POCO's (Business Logic, all rules and validation)
Entity Framework (Model, Data Access)
One note here is that ViewModel contains properties from multiple POCO's!
We inject the DataFactory through StructureMap and Unit test with xUnit along with Moq.
To answer you second question I would create a separate view only view to drop in as a user control. But you should still have a CRUD ViewModel in you app that encapsulate all that functionality in a user friendly way.
Thanks.
One reason for this VM abstraction is for testability. Another reason why you want a ViewModel is because it's basically a Data Transfer Object that might be a combination of fields from multiple models in a single container that is more relevant to your current view. Yet another reason to have VM is to take advantage of WPF two ways binding capabilities.
Using your regular model (plain POCO), you can update the View when your model change, but since your model does not implement dependency properties (most likely), you won't be able to take advantage of updating your model when the value in WPF control changes. Which mean you have to manual add a handler and do the copy this value from this control back to the model kind of thing.

How do you keep view logic out of the model and business logic out of the view-model in MVVM?

I can't quite figure out how to get the view model to be notified of changes in the model without adding a bunch of UI specific stuff like INotifyProperyChanged and INotifyCollectionChanged in my model or create tons of different events and do a bunch of things that feel like they're UI specific and should stay out of the model.
Otherwise I'd just have to duplicate all the business logic in the view-model to make sure everything is up to date, and then what's the point of having the model then?
One of the tricky ones that I have in my model is a property of a "Category" class. You can think of it as a tree structure and the property is all leaf-node descendants. Well in the model that property is generated on the fly recursively through all it's children, which is all fine and good. The view-model however needs to bind to that property and needs to know when it changes. Should I just change the model to accommodate the view-model? If I do then the view-model doesn't really do anything at this point, the model raises all the necessary notifications of changes and the view can just bind straight to the model. Also if the model was something I didn't have the source to, how would I get around this?
I disagree that INotifyPropertyChanged and INotifyCollectionChanged are UI-specific. They are in namespaces and assemblies that are not tied to any particular UI stack. For that reason, I typically put that kind of behavior as low in the system as I can (usually the data layer).
If there's some reason you don't want to put it at that level, that's fine. You can put it in at a higher level such as the service or UI layer. However, you need to make sure all changes to the data structures occur through that layer also.

What is the best way for the ViewModel to manipulate the View?

I understand that in the MVVM pattern, that a ViewModel should know nothing about the View.
So there seems to be two ways that the ViewModel can cause something particular to happen on the UI, consider this common flow of events:
user types something in a textbox
user clicks button
button calls DelegateCommand called "Save" on viewmodel
view model saves text from textbox
if everything goes well during the save, the view model changes its INotifyPropertyChanged property called SaveStatus to "Succeeded"
Now in the View, I have two ways to allow this change to have an effect on the UI:
in the View there could be a Textblock that has a Converter on it that converts the text of SaveStatus to a phrase such as "The save succeeded."
in the View there could be a Trigger that checks to see if SaveStatus = "Succeeded" and if so, then a series of Setters change the UI appropriately (hiding elements, changing texts, changing colors, etc.)
Is this the basic flow of information from ModelView to View that you use in your applications?
You can also create custom events on the viewmodel and have the view subscribe to them and react accordingly. You shouldn't need to do this very often, but it makes more sense than inspecting every INotifyPropertyChanged event for particular property names.
Is this the basic flow of information from ModelView to View that you use in your applications?
Yes. We use INotifyPropertyChanged almost exclusively for changes from the ViewModel to the view. Where the interaction is a bit more complex we use other events that the View hooks up to.
Instead of a SaveStatus message property we have a HasChanges boolean on an EditableAdapter, which wraps our POCO and provides commit/rollback of changes, as well as other calculated properties. Then we can bind our Views to this HasChanges so that, for example, we can display the documents name with a * on the end to show it has changes, or use the HasChanges to disable/enable a Save button.
We are using the model view controller pattern, so it goes like this:
user types something in a textbox
user clicks save button
the view tells the controller to save the data
the controller tells the view to fetch the data
the controller saves the data to the model
the controller signalizes the view that the save succeeded
the view shows "The save has succeeded"
I think you could use pretty much the same approach (the only difference would be that controller and model would be both the view model in your example)

Resources