Multiple ViewModels for Add and Edit (WPF, MVVM) - mvvm

I have done some research online and I have come up with some conflicting answers. Here is my situation:
I have a EditClient view which references the ClientViewModel and I have an AddClient view which also references the ClientViewModel. Naturally, edit and add operations are different and the logic in the ViewModel differs somewhat.
Would it be appropriate to have an EditViewModel and an AddViewModel and have them referenced by their respective views? Is this considered valid MVVM structure?
Thanks!

Yes, i would have one ViewModel per View. But the ViewModel would of course work with the same Model.

Related

How to refactor viewmodels

Currently i am working on a project using prism where one of our modules has a viewmodel with 3000 lines of code!!!. really I would split this class to little pieces (some time is hard to read the code inside of this viewmodel)
Actually the code of the viewmodel has more less 30 properties related with commands and i think there it's good place to start.. (some idea how can i move these commands to other class?)
any ideas?
Thank you!
There are a few things you can do, firstly how much of the code should be in the view model, and how much of it should be in the model itself?
Secondly, can any of the code be part of services that the view model takes as a dependency?
Thirdly, you might want to consider a conventions based MVVM framework such as Caliburn.Micro which will allow you to use actions instead of WPF commanding, which means considerably less boilerplate code binding up verbs on your view model with events on your view, as well as other advantages.

iPhone MVC Question on table views and structuring custom class models

I have been reading a lot about MVC these days and I think I have my head around it but I would appreciate some advice and informed opinions on how to best approach my problem.
I have 3 questions really all related to the MVC design pattern.
In many of the examples I have encountered people have used the contoller (say of a Table view) to populate an array with objects of a custom class (say Student.h/m).
But shouldn't the Student class have methods that are called that would return an array of data for the variable in the controller? Isn't that how the MVC works? That the model holds the definition of the data and takes responsibility for reading and writing it?
In many table view examples, in the various books I have read, they all say, "for convenience we are going to make the controller our delegate and data source for the table". I have yet to see an example where table view does not use the controller as a data source. How would you hook up a table view to a different data source?
I have 2 model classes "mission" and "airfield". Each one of these needs data from a XML file in the cloud. Do I write the parser in the mission/airfield implementation files? Do I create a separate Parser object? Should these models retun data to the controller as an array?
Whilst I understand a lot of the theory a lot of the examples I find on the web seem to break a lot of the concepts I thought I understood.
Any explanations would be most welcome. The quality of responses on this site are amazing.
Thanks in advance
You seem to already have a pretty good understanding of how MVC works, so I'll just add a few comments.
The controller is responsible for feeding data to the view.
There could be a million different states and scenarios that would affect what data to use and how, and it's not the model's job to figure that out. The model holds the data, and the controller handles the logic.
If you need a different delegate or data source for your table view, you can instantiate them in the table view controller, and then tell the table view about them using the delegate and dataSource properties. They need to implement the required methods of the UITableViewDelegate and UITableViewDataSource protocols.
Sometimes models and controllers overlap in functionality, and this is a perfect example of such a case.
One solution could be to let the mission and airfield classes inherit from a custom class that knows how to download the required XML and set up a parser, so they just need to provide the URL and override the parser callbacks for their specific tags. Everything else related to downloading the XML could be handled in the super class.
Another way could be to create a separate class that takes a URL and returns some XML, and then the mission and airfield classes call that method and parse the XML independently.
The wrong way is to let both the mission and airfield classes know how to download and parse, because you'd have to maintain the code in both places.
It's OK to have a data loading controller, that hands over the data to the view controller, so the controller code can be very specific (and maintainable).

ViewModel as member of ViewModel

I have been using the MVVM Light Toolkit to help learn the MVVM pattern. However, I have not been able to solve the problem of usercontrols within controls scenario.
For example, in a Timesheet application, lets say we have a control called NewUnitOfWork. When it first loads, a panel with a ListBox with a list of projects is loaded as the Content of the NewUnitOfWork. The user clicks on one. A new panel is swapped in with a ListBox containing the possible tasks for that project. A task is selected and a new panel is loaded which will contain controls to input data for the chosen task of the chosen project.
So, we have the selected item in one usercontrol being passed to the other two user controls, which are, in turn swapped in as the Content of the NewUnitOfWork control (or window).
If each control has its own ViewModel, we need to pass the selected value from one ViewModel to the next etc.
I have got it working in a single user situation using global variables (via a "service"). However, there are concurrency issues with that and it is not a good solution. It's sub-par.
I have seen many times the suggestion on this forum to have on ViewModel as a member of another ViewModel. Whilst this solves the problem at hand, I believe it is a violation of the MVVM pattern. Another ViewModel is not UI-related functionality that the ViewModel shoule be directly.
So. Has anyone found a clean MVVM-complying way to do this sort of thing?
Cheers
Please always keep in mind that MVVM is just a pattern and it is designed to help you separate your UI and logic. Do not be afraid to “violate the pattern” if it helps to increase testability or maintainability of the application.
Having a master ViewModel with several child ViewModels is very handy if you have a complex UI. The main ViewModel may be responsible for handling the top level UI controls and for coordination of the child VMs, while other ViewModels are responsible for communication with the sub regions of your UI.
Moreover, if you have a really complex UI with the multiple nesting UI layers, you can implement an infrastructure to automatically cascade all the events from master to child VMs.
And of cause, you may try to use one of the more advanced MVVM frameworks. For example Catel implements pretty comprehensive model to resolve such situations with nested VMs.
I don't see a problem with ViewModels referencing other ViewModels (based on my experience with TreeViews). Have a look at any article about TreeView and MVVM. You will see that each node is a ViewModel, that references a collection of child nodes, which are ViewModels. Trying to do that without VM-VM references would be a nightmare.
Josh Smith
http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx
I have been using the following setup:
A 'master' VM with a 'collection' VM and a 'details' VM as nested properties.
The master VM is tied to a View that is used as a master-detail form. This master-detail View is composed from two other Views.
I find it a very neat setup because it allows me to put search criteria in the master View(Model) and keeps the other View(Model)s clean.
I can't see how this would break the pattern.

MVVM: Does the ViewModel format the data it gets from the model?

I'm a little confused about MVVM.
I understand the concept and can see the advantages. My problem is: does the ViewModel pass data directly from the model.
For example, let's say I have a "User" model with a findByName() method. The ViewModel would call this in order to pass
the relevant user details to the view.
The model would likely retrun a set of "User" objects each which has properties such as name, email address etc and may also have methods.
My question is, should the ViewModel return the set of User objects to the view, or return a restructured version of this which
contains only what the view needs?
As I understand it, the "User" object in this case is part of the model layer and in MVVM the View should be dependant only on the ViewModel.
My issue with this is the ammount of seemingly redundant binding logic required in the ViewModel that would be created to restructure the output.
Passing the set of User objects directly to the View (via the ViewModel) would be far simpler.
There's a little bit of redundancy, sure. However, if you implement MVVM by presenting the objects, you get to
format the model information for the view without polluting the model with presentation logic
notify the view when anything changes
use WPF's validation (if you're using WPF)
run acceptance tests from the VM level rather than the GUI if you want to
abstract your presentation away from any changes to the model.
That last one's important. Mostly presentation bindings nowadays are dynamic and fail silently - web pages, WPF, you name it. That means that if someone decides to rename something on the model, it will suddenly break in your GUI and you won't know.
By putting a VM between your Model and View you buffer yourself from changes like this.
If you want to go ahead and get something working with the Users as they are, I say go for it - it'll help you get fast feedback on your GUI. However, the first time those User objects don't do exactly what the View needs, or you need to notify the View of a change, or you find yourself polluting the model, or something in the binding breaks, maybe that's a good time to move to MVVM.
Doesn't that just move the break to the ViewModels which are using the model? You'd still need to go through and update all of those.
If I renamed something (e.g. changed "surname" to "lastname") I'd expect things to break. I don't see how adding the binding in the VM layer fixes that.

MVVM View reference to ViewModel

I'm using MVVM in a WPF app. I'm very new to both. Let me state that I am not a purist in the MVVM pattern, I am trying to use as many best practices as I can but am trying to make what I think are reasonable compromises to make it work in our environment. For example, I am not trying to achieve 0% code in my View code-behind.
I have a couple of questions about best practices.
1) I understand I don't want my VM to know about the attached View, but is it reasonable for the View to have a reference to its VM?
2) If a control in a View opens another View (such as a dialog) should I handle this in the View? It seems wrong to handle it in the VM since then the VM has some knowledge of a specific View.
1) The View has definitely a reference to the ViewModel through the DataContext. And you are allowed to cast the DataContext in your View:
public class ShellView : Window
{
…
public ShellViewModel { get { return DataContext as ShellViewModel; } }
This isn’t a violation with the Model-View-ViewModel pattern.
.
2) You are right. A ViewModel shouldn’t open another View. A better approach is to use Controllers. They are responsible for the Workflow of an application.
If you are interested in more detailed information then you might have a look at the WPF Application Framework (WAF).
1) Here are two simple practices for View's "knowing about" a ViewModel. It's reasonable for a View to know about a ViewModel (for Data Binding) -- but you may not need it in your case. See if either of these approaches help solve your problem. There are other ways, but these should be simple enough:
public View(ViewModel vm)
{
View.DataContext = vm;
}
public Bootstrapper(View v, ViewModel vm)
{
v.DataContext = vm;
//or, if you want it to have no parameters
View v = new View();
ViewModel vm = new ViewModel();
v.DataContext = vm;
}
The first option isn't bad if you have a service location tool, but there is a flavor of MVVM that doesn't like any code in the View's Code-Behind. The second option isn't bad either, should be simple enough for your task.
2.) This question can be a bit of a sticky point in MVVM design. If we are talking about a general Win32 MessageBox, I will often separate that logic into an additional object and put it in the VM. This way tends to a little more clear. (For example, I have selected an item in a ListBox, I have attached a Delete ICommand to that action, and in my ViewModel when this ICommand is Executed, I will poke my MessageBoxObject to ask if the user "wants to really delete" this item). More advanced "Dialogs" would use additional ViewModels and DataTemplates for those ViewModels. I prefer the Mediator approach.
1). The view will need a reference to the view model at some level, since the viewmodel will act as the view's datacontext.
2) One way to handle this is to have a generalized viewmodel representing a dialog, that is owned by the main viewmodel (the one being used as the views datacontext.)
You can use a command to crate a new instance of a dialog viewmodel, which will have a corresponding datatemplate defined in your resources. This template will be set to bind to the dialogviewmodel type.
Quite late, but I think this is tricky enough to deserve lots of different perspectives.
I understand I don't want my VM to know about the attached View, but
is it reasonable for the View to have a reference to its VM?
As already answered, a proper View-ViewModel arrangement involves the ViewModel being assigned as the View's DataContext property. That allows DataBindings to be "automagically" established from declarative XAML, or fine-tuned via code behind.
Sometimes, you'll be tempted to write, in your code behind, something like this:
var dc = DataContext as CleverViewModel;
CleverViewModel.CleverProperty.Add(someValue); // just a simple example
I believe the proper way to achieve this sort of things is NOT to cast DataContext, but instead:
Have some dedicated control in View, for example an ItemsControl with its ItemsSource two-way databound to some property in viewmodel:
<ItemsSource x:Name="cleverControl" Visibility="Collapsed" ItemsSource="{Binding CleverProperty, Mode=TwoWay}"/>
Cast the bound property instead of the whole ViewModel, in code behind:
var collection = (ObservableCollection<double>)cleverControl.ItemsSource;
collection.Add(someValue);
Note the important difference: the second approach in this example doesn't require the View to know the ViewModel type, it only needs a property named CleverProperty of type ObservableCollection<double>. This allows me to have polymorphic or even duck-typed ViewModels.
If a control in a View opens another View (such as a dialog) should I
handle this in the View? It seems wrong to handle it in the VM since
then the VM has some knowledge of a specific View.
This shouldn't happen in strict MVVM, and its not difficult to avoid using DataTemplates. DataTemplates map a given type of DataContext to a given type of view, so anytime the datacontext of a ContentControl changes, its display also changes, provided that you have a DataTemplate for that type:
A control in the view could send a command to the ViewModel, which in turn would update some of its own properties, that would be reflected by the view.
A View could contain another View, outside the knowledge of the ViewModel. In this case, the code behind can manipulate the datacontext of the contained view.
There are more subtleties, but I have been using this approach with good results. Hope this helps someone.
Build Your Own MVVM Framework
I found the approach suggested by Rob Eisenberg very interesting.
Key points:
Convention over configuration
ViewModel first
Which is very similar to ASP.NET MVC philosophy.
I highly recommend watching the video.