WPF/MVVM - should view-models stay constant and just the model change? - wpf

I'm a bit in doubt as to what is 'the right way'.
I have an application with concepts like visual studio, so I'll use that to explain:
I have a 'solution' view model and a model behind. The view model is displayed in a 'explorer'.
I can change between the situations where 'no solution is loaded' to 'a solution is loaded' and back.
And finally my question :-) :
Should I keep my view model object and let it reflect that I have a new 'solution object' loaded? Or should I create a new view model object and let the view bind to the new object?

Your Viewmodel contains the state of any data associated with the UI which is not further back in the Model.
One way I answer questions such as yours is by considering what behaviour I want in the UI and what needs binding to some state information. Or, to put it a different way, any time that I feel like writing some code that would cause UI elements to be shown or hidden, think about how that maps to a boolean variable.
So, take large chunks of the UI that only are visible when you have a Model loaded. These might have their visibility bound to a boolean property in the Viewmodel IsSolutionLoaded.
Maybe you want to disable some things if processing is occurring, you could have a property IsCompiling. I've used this approach with a property NotRunningthreadedProcessing as shown below, that let me disable controls when a synchronisation object existed in the Viewmodel.
CNTL_WhiteLevel.SetBinding(ProgressBar.IsEnabledProperty,
new Binding("NotRunningThreadedProcessing"));
// and the C++/CLI property concerned
property bool NotRunningThreadedProcessing {
bool get()
{
return mThreadedCommandSyncher == nullptr;
}
};

What is the arrengement of the ViewModel?
In General
View Model is the localized version of actualmodel and View is updated whenever there is a change i its viewModel through DataBiding.
in your case ,you have 2 states.
1- Your View is Loaded
2- Your View is not loaded
so should I create a new view model object and let the view bind to the new object?
in my thoughts ,YES

Related

wpf MVVM ObservableCollection

My model has a couple properties one is a string and the other is an observablecolletion. When the model is created it fires off a backgroundworker thread to basically poll a .dll for data. Based on the data it receives it will either set the string and/or add and item to observable collection. My string property seems to fire its Onproperty change just fine and the view updates. However, my observable Collection throws a cross thread exception. I have tried moving code where i set the ObesrvableCollection to the worker.ReportProgress and get the same error. I have moved the logic into the view model and still get the same threading error. I'm unsure why my string property works for one. I have read about Dispatcher.Invoke, but i'm pretty sure that my model should not be aware of this. Can anyone explain the correct way to go about this please.
Just fyi - my view is not tied directly to my model. I have a property for my model in my viewModel and the model gets passed through constructor injection. Just want to put that out there before anyone thinks my model is talking directly to the the view.
Hard to give specifics without code. However, WPF automatically marshals property change notifications for scalar properties but not collections. Hence, you must be modifying the collection from a non-UI thread.
There is no reason why your VM can't use Dispatcher, or perhaps the more generic SynchronizationContext if you prefer. It can make things more tricky to test, however.
If you post code there may be a way you can simplify things.
As Kent said, if you're not on the UI you need to use the Dispatcher to update your collection:
Application.Current.Dispatcher.Invoke(new Action(() =>
{
// update your ObservableCollection here
}));

designing model in MVVM and WPF and state management

In my WPF app, I am using MVVM. I am reading from an XML file, deserialize it to an object model and keeping it in memory.
XML File->BusinessObjectModel(Model)->ViewModel
Whenever the viewmodel needs the model I will provide it from the memory.My problem is when I use the model elements in the views it is updating the model in memory(obviously!). I dont want to do that, I want the model updated only when the user clicks OK in the view(or dialog). How is it usually achieved? Should I only provide the viewmodel a clone of the model and not the original reference?
Editing a clone of the model object would solve the problem, as you suggested.
Another approach would be to have the property bindings use an UpdateSourceTrigger of Explicit. Upon clicking Save, you would programmaticcally call UpdateSource on each binding expression. This requires some extra code, which would belong in the View's code-behind since it is code that manipulates UI elements.
Also consider having a property on your VM for each property exposed in the View, where the backing field of the VM property is not the wrapped Model object's corresponding property. When the user clicks Save, you could then assign each property from the VM to the Model object. Naturally the controls in the View would be bound to the VM properties, not the Model properties. This is effectively like having a clone, without the extra baggage of supporting cloning in the Model layer.
I'm not suggesting that any of these options are better or worse. It all depends on the context in which they are used.

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

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)

Silverlight MVVM linking model and view model

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.

Resources