Creating a tabcontrol in MVVM from a central datasource - wpf

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

Related

WPF: How to trigger GUI behaviours in response to view-model events?

I'm developing a WPF/MVVM application and I have a listbox binding to data in a ViewModel. At various points I need the view model to cause the listbox to scroll to a given element.
How can I do this without creating a custom control and while still maintaining good separation of concerns?
I've currently got it working by creating a custom behavior class in the view layer with a dependency property VisibleIndex which the XAML code then binds to an integer in the view model:
<ListBox x:Name="myListBox"
local:ListBoxVisibilityBehavior.VisibleIndex="{Binding VisibleIndex}">
When the integer is set it triggers the dependency properties update handler which tells the listbox to scroll to the associated index.
This seems a bit hacky though because the dependency property value is never changed by the listbox and the update handler only gets called when the value changes, so the only way to ensure that the relevent item is visible is to do something like this:
// view-model code
this.VisibleIndex = -1;
this.VisibleIndex = 10;
The only reason I'm using a behaviour class at the moment is for binding my custom dependency property, is there a way to do something like this with events instead?
Attached properties are somewhat required in your case - as at some point, 'somewhere' you need to call the following method...
ListBox.ScrollIntoView(item)
or
ListBoxItem.BringIntoView();
And for that you need some sort of code behind - and attached properties/behaviors are a nice way of packaging that, w/o impacting your MVVM.
Having said that - if you just need to have your 'selected item' scrolled into view at all times (which is the case most of the time). Then you could use a different attached-property based solution (that again):
mvvm how to make a list view auto scroll to a new Item in a list view
All you have to do then is to set or bind to SelectedItem.
That's a bit 'nicer' if you wish - but the mechanism is the same.
For anyone else interested in the answer to this one of the MS engineers on the WPF forum cleared it up for me. Instead of binding to an event directly you bind to a wrapper object that encapsulates that event. The behaviour can then grab the reference to the wrapper from its DP and do whatever it wants with it i.e. subscribe to the event, trigger it etc.

Building a data entry form in wpf

I'm trying to build a data entry form in wpf. To perform validation I apparently need to have an object attached in the datacontext of my grid. But how can I have one when I didn't create one yet?
How does it work?
For example, I have a screen with a datagrid. The datagrid contains users that were obtained from membership. Above the grid is a button: add user. When clicked a new window appears and the following can be entered: user name, password, email. To perform validation on the textboxes to see if they aren't empty. Now, it is my understanding that the way this works is by having an object attached to the window (datagrid datacontext). But how can I have it attached when it doesn't exist yet?
This is a case where MVVM design patterns are very useful.
Every WPF view has a corresponding view model object that the properties in the view are bound to. So your window with the data grid has a view model - its DataContext - and the view model has properties that are bound to properties in the view - e.g. the ItemsSource in the data grid is bound to a collection (see note 1).
The "add user" command (which is implemented as a RelayCommand in the window's view model) creates a new view (the new window) and its corresponding view model object (the new user), sets the view's DataContext to the view model, and calls ShowDialog to show the window. (See note 2.) If the user accepts the new object, ShowDialog returns true, and the logic in the command takes the view model object (which now contains whatever changes the user made) and uses the information in it to create a new model object and add it to the model. If the user cancels, ShowDialog returns false, and the command discards the view model object without creating a new model object.
Note 1: The collection here may be a collection of model objects, or it may be a collection of view model objects. It depends on whether or not you need anything that's not in the model for displaying the model objects in a data grid. It's common, in this kind of scenario, for the objects in the grid to be view models for the dialog - that is, the view model objects have properties implemented for both display in the grid and modification in the dialog window. On the other hand, if all the grid is doing is displaying data from the model, there may be no need for an intermediary object.
Note 2: Having the command create a WPF window violates a central MVVM design principle, which is that view models shouldn't create WPF objects. The reason for this principle is pretty simple: you can't build an automated unit test for this command, since it's just going to throw up a dialog and wait. There are all kinds of different approaches to this - see, for instance, this question, and Josh Smith's blog post on the Mediator pattern - and all of them involve delegating the creation and display of the actual dialog window to a separate service that can be mocked out for unit testing. If you don't want to choose one of those approaches up front, you can retrofit one into your application once you get this thing working.
The idea here is that you should attach an object which is slightly different from your business models. In your case it won't UserInfo (or whatever you have for users in grid). It will be some other class, more suitable for editing. In MVVM this class will be a ViewModel. This class will have some differences comparing to your regular user class, for example it may have some properties nullable (when you haven't set them yet). Also this class will handle validation. You should instantiate this class at the same time you're creating an editor window and put instance of this class into Window.DataContext.
Hmm, there is a lot in this question but I just created a screen with three data grids (I am using Telerik in this case) and under each datagrid is a button to add to the grid. No the window with the three datagrids has it's own view model. and each of the "pop up's" has it's own viewmodel, in this case all of these are user controls and I just create a new window and set window.content and call show dialog.
Communication is facilitated via "events" - not the standard events you are used to in .NET but in this case I am using Prism and it's CompositePresentationEvent class. When the user is done creating their new object they click add and I fire off this event with the "payload" being the object they created. The main window with the three grids listens for that event and has a method to handle it, in this case adds it to the ObservableCollection which is what I bind the grids to.
If I were you I would look into the various frameworks that are out there, Prism, MVVM light etc... Again, your question seemed rather broad, I tried to give an overview but I didn't go into detail, if you look into some sort of framework I think it will clear up a lot of these details for you.
When the users hit Add New, create a new blank copy of your object, and set the datacontext to that new object.
Set some kind of flag to identify that it is a New object. This can be the Id being NULL, 0, -1, etc or an ObjectState property set to New. That way all your validation rules apply, and once the user hits save you know to INSERT instead of UPDATE

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.

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