Startup Sequence for C# WPF MVVM Applications - c#

I'm currently going back to designing some GUI Applications using WPF + MVVM, I now find it much easier to understand than when I first encountered it.
One question that troubles me however is the startup of the application. From my view, there are two approaches:
Start from the Main Window View, have its ViewModel be instantiated by some means which again instantiates the Model it represents. This puts the View / GUI in the "operating" position.
The other way would be to override the OnStartup routine in the Application class (John Smith does it this way in his The MVVM-Design Pattern MSDN Article) and start by creating the model, passing it to the ViewModel Contructor and assign the newly created ViewModel to the DataContext of a separately created View / Window.
Is either way fine (in this case, what may be reasons to prefer one over the other) or is one violating MVVM rules?

Your first approach is correct:
Start from the Main Window View, have its ViewModel be instantiated by
some means which again instantiates the Model it represents. This puts
the View / GUI in the "operating" position.
The viewmodel then becomes the DC for the View. There should be a 1:1 of View to ViewModel.
You want each class to be able to be instantiated with as few dependencies as possible.
My ViewModel ctors really only consist of an argument for passing a class containing View-Specific callbacks, based on an interface.
Model m = null;
IViewCallbacks cb;
public MainViewModel(IViewCallbacks mainViewCallbacks)
{
this.cb = mainViewCallbacks;
m = new Model();
}
The ViewModel instance has instances of the model(s) that I need to be able to access. The vm backing the view should be the in charge of instantiating these, otherwise your unit testing is going to suffer because of external dependencies (that instance of the model that you need to pass in via the ctor).

Related

Advice on setting up model in a MVVM application using caliburn

I'm new to MVVM so I'm trying to figure out what is the best way to do this. I'm using WPF with Caliburn Micro for this.
I have two different views (each with their view models) for the model I'm trying to manipulate. One view shows the model in a tree view while the other shows a table view of the data.
My model basically looks something like the following
public class Foo
{
public string Name {get;set;}
public string[] Categories {get;set;}
}
The Views are different ways to visualize collections of Foo. The table view is pretty straightforward, but the tree-view will group Foo by the category it contains.
So if an instance of Foo is something like
var fo = new Foo(){Name="one",Categories=new[]{"a","b","c"}};
Then the treeview would be
a
|_ one
b
|_ one
c
|_ one
I have two questions about how to connect the model to the view model in the spirit of MVVM.
What is the best way to populate the viewmodels from the model for the different views? I was thinking something like a singleton FooManager that is accessed from the view models. Or would using the caliburns SimpleContainer be better suited for this?
Lets say I manipulate Foo in the table view by changing it's category collection. How would I propagate the change to the treeview, since that would mean that Foo would appear in a different tree node? Would Foo need to implement PropertyChangedBase' and somehow bubble up the changes to the other ViewModel? Or would it be better forFooManagerto implementPropertyChangedBase`. Seems like the latter would be more reasonable.
TIA
For collections that change reference BindableCollection and are presented on the view.
As for bringing data into a view you can do it through a combination of DI/IoC, via constructor injections on the ViewModel in question. Most of that is done thru Interfaces that can be found in the Container of your choosing either SimpleContainer to MEF if you prefer or what ever IOC/DI container you choose really, the framework is such that can be extended with any container. Going with Interfaces allows for mocking and unit testing of the viewmodels.
Yes bubbling of the change to the View is usually done through what you had though by means of implementing INotifyPropertyChange which is part of the PropertyChangedBase class object.
One thing that will probably rear its ugly head is that Collections based off ObservableCollection don't necessarily bubble the changes of the underlying item's properties in the collection, that is an entirely different thread on SO

Driving a MVVM application

Given any intermediate MVVM application which has more than 5 views and viewmodels, are there any recommend design patterns of how to do the scaffolding of such an application?
Right now I usually have a controller which is created in App.OnStartup which:
sets up the main view
injects subviews (typically I have a MainWindow with status bar and navigation, which has "inner windows")
handles the marriage of views and viewmodels.
handles navigation (going from view A to view B)
supports breadcrumb navigation (and things like the typical NavigationService.GoBack())
I believe there are already good design patterns, but non of them I have heard of or read about.
So the question is:
Is there any commonly accepted pattern of how to handle the coupling of viewmodel and view (setting the datacontext) and the navigation between views?
In my opinion both view-first (setting the DataContext in XAML) and ViewModel-First (let the viewmodel get the view injected via DI/IOC) are not that good because they have make up dependencies between view and viewmodel.
Plain MVVM makes no assumptions on how to set up the whole MVVM machine.
I'm just wondering that this quite common problem has no "of-the-shelf" solution.
Controllers are widely used I believe. How do others solve that?
Some design patterns to consider are Inversion of Control (IoC) and Event Aggregator.
For C# / MVVM, the Caliburn Micro Framework (is one of a couple that) makes IoC and Event Aggregator much easier.
You correctly identified a core concern of MVVM in that there is no off-the-shelf solution to truely decouple the ViewModel from the View. It is a core concept that ViewModels are purpose built to be pared with Views. The issue comes down to how to manage instances of ViewModel / View pairings.
View first approach assumes that the View knows about and can instantiate ViewModels as needed - this is a problem for SoC because any View class now has multiple responsibilities; spinning up a ViewModel, and handling UI.
View Model first is difficult because it often leads to breaking one of the main tennants of MVVM - that the VM should be testable without any associated views.
This is where IoC comes in, typically. The IoC typically resides in the View layer (this is to allow it to have access to all View and ViewModel classes as needed) it need not be a View itself. It's often better to think of your IoC manager as a Controller - which kind of leads to a pseudo pattern of MVCVM. The sole purpose of this "controler" becomes providing View and ViewModel instance pairings to whoever needs it.
Event Aggregator pattern really helps with this because classes in the ViewModel and View no longer need to worry about who they are paired with, and can interract only with other classes in their own level. A particular View Model need not care who sent the event "Update Load Progress" all it needs to be responsible for processing the results of the event by setting it's progress property.
Regarding the "link" between the View and the ViewModel, I found the concept of the DataTemplateManager in this post really interesting. Basically, it allows you to do things like
DataTemplateManager.Register<TViewModel1,TView1>();
DataTemplateManager.Register<TViewModel2,TView2>();
DataTemplateManager.Register<TViewModel3,TView3>();
it might not be the best solution, admittedly, but is pretty handy. I already incorporated that into my own homemade MVVM framework.
I have a smallish project that contains a singleton class called ViewFinder that has a couple static methods called MakeWindowFor(vm) and MakeDialogFor(vm), that both take the viewmodel as a parameter. ViewFinder has a Dictionary that I fill that links viewmodels with the windows I've set to correspond to them. More information could be added, because perhaps the view lives inside another instead of simply being a window.
This may not be the best way to accomplish the task, but works for my needs on this project, and keeps the viewmodels unaware of the actual view implementation. The ancestor of all my viewmodels contains events for things like displaying message boxes, and all my windows are descended from a base class that know how to subscribe and react to these common events.
public class ViewFinder {
private static ViewFinder m_Instance;
public static ViewFinder Instance {
get {
if (m_Instance == null)
m_Instance = new ViewFinder();
return (m_Instance);
}
}
/// Maps viewmodels to windows/dialogs. The key is the type of the viewmodel, the value is the type of the window.
private Dictionary<Type, Type> ViewDictionary = new Dictionary<Type, Type>();
/// Private constructor because this is a singleton class.
///
/// Registers the viewmodels/views.
private ViewFinder() {
Register(typeof(SomeViewModel), typeof(SomeWindowsForViewModel));
Register(typeof(SomeViewModel2), typeof(SomeWindowsForViewModel2));
}
/// Registers a window with a viewmodel for later lookup.
/// <param name="viewModelType">The Type of the viewmodel. Must descend from ViewModelBase.</param>
/// <param name="windowType">The Type of the view. Must descend from WindowBase.</param>
public void Register(Type viewModelType, Type windowType) {
if (viewModelType == null)
throw new ArgumentNullException("viewModelType");
if (windowType == null)
throw new ArgumentNullException("windowType");
if (!viewModelType.IsSubclassOf(typeof(ViewModelBase)))
throw new ArgumentException("viewModelType must derive from ViewModelBase.");
if (!windowType.IsSubclassOf(typeof(WindowBase)))
throw new ArgumentException("windowType must derive from WindowBase.");
ViewDictionary.Add(viewModelType, windowType);
}
/// Finds the window registered for the viewmodel and shows it in a non-modal way.
public void MakeWindowFor(ViewModelBase viewModel) {
Window win = CreateWindow(viewModel);
win.Show();
}
/// Finds a window for a viewmodel and shows it with ShowDialog().
public bool? MakeDialogFor(ViewModelBase viewModel) {
Window win = CreateWindow(viewModel);
return (win.ShowDialog());
}
/// Helper function that searches through the ViewDictionary and finds a window. The window is not shown here,
/// because it might be a regular non-modal window or a dialog.
private Window CreateWindow(ViewModelBase viewModel) {
Type viewType = ViewDictionary[viewModel.GetType()] as Type;
if (viewType == null)
throw new Exception(String.Format("ViewFinder can't find a view for type '{0}'.", viewModel.GetType().Name));
Window win = Activator.CreateInstance(viewType) as Window;
if (win == null)
throw new Exception(String.Format("Activator returned null while trying to create instance of '{0}'.", viewType.Name));
win.DataContext = viewModel;
return win;
}
}

Is it OK to instantiate presenters within Main using MVP approach?

I wanted to use a "presenter first" approach (the presenter attaches itself to it's view and model in the Constructor using dependency injection via the constructor call).
My form is a single MainForm containing two user controls which each have their own presenters, but share the model, so I create all the presenters in Main, passing in the relevant user control to the presenter by having a property which exposes these controls from FormMain, and passing in a single instance of the model to all presenters.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
IDocumotiveCaptureView view = new DocumotiveCaptureView(); //this is the MainForm
IDocumentModel model = new DocumentModel(); //single model
IDocumotiveCapturePresenter Presenter = new DocumotiveCapturePresenter(view, model); //MainForm's presenter
IControlsPresenter ControlsPresenter = new ControlsPresenter(view.ControlsView, model); //ControlsPresenter - attached to the user control via view.ControlsView
IDocumentPresenter DocumentPresenter = new DocumentPresenter(view.DocumentView, model);//DocumentPresenter - attached to the user control via view.DocumentView)
Application.Run((Form)view);
}
Can anyone see anything inherently bad or wrong in this approach? I realise this MAY be subjective, but I'm very new to MVP and would like some feedback.
If it works for you, then of course it's ok. MVP isn't a religion. It's not even considered a single pattern anymore. The two most popular interpretations seems now to be Passive View and Supervising controller.
The Main method in your case is your composition root (search for any answers by Mark Seeman) and it's an excellent place to do what you do. But it's not the only place to do it.
For more MVP in WinForms, please see Model-View-Presenter in WinForms

MVVM: Binding to Model while keeping Model in sync with a server version

I've spent quite some time to try and find an elegant solution for the following challenge. I've been unable to find a solution that's more than a hack around the problem.
I've got a simple setup of a View, ViewModel and a Model. I will keep it very simple for the sake of explanation.
The Model has a single property called Title of type String.
The Model is the DataContext for the View.
The View has a TextBlock thats databound to Title on the Model.
The ViewModel has a method called Save() that will save the Model to a Server
The Server can push changes made to the Model
So far so good. Now there are two adjustments I need to make in order to keep the Model in sync with a Server. The type of server is not important. Just know that I need to call Save() in order to push the Model to the Server.
Adjustment 1:
The Model.Title property will need to call RaisePropertyChanged() in order to translate changes made to the Model by the Server to the View. This works nicely since the Model is the DataContext for the View
Not too bad.
Adjustment 2:
Next step is to call Save() to save changes made from the View to the Model on the Server. This is where I get stuck. I can handle the Model.PropertyChanged event on the ViewModel that calls Save() when the Model gets changed but this makes it echo changes made by the Server.
I'm looking for an elegant and logical solution and am willing to change my architecture if it makes sense.
In the past I 've written an application that supports "live" editing of data objects from multiple locations: many instances of the app can edit the same object at the same time, and when someone pushes changes to the server everyone else gets notified and (in the simplest scenario) sees those changes immediately. Here's a summary of how it was designed.
Setup
Views always bind to ViewModels. I know it's a lot of boilerplate, but binding directly to Models is not acceptable in any but the simplest scenarios; it's also not in the spirit of MVVM.
ViewModels have sole responsibility for pushing changes. This obviously includes pushing changes to the server, but it could also include pushing changes to other components of the application.
To do this, ViewModels might want to clone the Models they wrap so that they can provide transaction semantics to the rest of the app as they provide to the server (i.e. you can choose when to push changes to the rest of the app, which you cannot do if everyone directly binds to the same Model instance). Isolating changes like this requires still more work, but it also opens up powerful possibilities (e.g. undoing changes is trivial: just don't push them).
ViewModels have a dependency on some kind of Data Service. The Data Service is an application component that sits between the data store and the consumers and handles all communication between them. Whenever a ViewModel clones its Model it also subscribes to appropriate "data store changed" events that the Data Service exposes.
This allows ViewModels to be notified of changes to "their" model that other ViewModels have pushed to the data store and react appropriately. With proper abstraction, the data store can also be anything at all (e.g. a WCF service in that specific application).
Workflow
A ViewModel is created and assigned ownership of a Model. It immediately clones the Model and exposes this clone to the View. Having a dependency on the Data Service, it tells the DS that it wants to subscribe to notifications for updates this specific Model. The ViewModel does not know what it is that identifies its Model (the "primary key"), but it doesn't need to because that's a responsibility of the DS.
When the user finishes editing they interact with the View which invokes a Command on the VM. The VM then calls into the DS, pushing the changes made to its cloned Model.
The DS persists the changes and additionally raises an event that notifies all other interested VMs that changes to Model X have been made; the new version of the Model is supplied as part of the event arguments.
Other VMs that have been assigned ownership of the same Model now know that external changes have arrived. They can now decide how to update the View having all pieces of the puzzle at hand (the "previous" version of the Model, which was cloned; the "dirty" version, which is the clone; and the "current" version, which was pushed as part of the event arguments).
Notes
The Model's INotifyPropertyChanged is used only by the View; if the ViewModel wants to know whether the Model is "dirty", it can always compare the clone to the original version (if it has been kept around, which I recommend if possible).
The ViewModel pushes changes to the Server atomically, which is good because it ensures that the data store is always in a consistent state. This is a design choice, and if you want to do things differently another design would be more appropriate.
The Server can opt to not raise the "Model changed" event for the ViewModel that was responsible for this change if the ViewModel passes this as a parameter to the "push changes" call. Even if it does not, the ViewModel can choose to do nothing if it sees that the "current" version of the Model is identical to its own clone.
With enough abstraction, changes can be pushed to other processes running on other machines as easily as they can be pushed to other Views in your shell.
Hope this helps; I can offer more clarification if required.
I would suggest adding Controllers to the MVVM mix (MVCVM?) to simplify the update pattern.
The controller listens for changes at a higher level and propagates changes between the Model and ViewModel.
The basic rules to keep things clean are:
ViewModels are just dumb containers that hold a certain shape of data. They do not know where the data comes from or where it is displayed.
Views display a certain shape of data (via bindings to a view model).
They do not know where the data comes from, only how to display it.
Models supply real data. They do not know where it is consumed.
Controllers implement logic. Things like supplying the code for ICommands in VMs, listening for changes to data etc. They populate VMs from Models. It makes sense to have them listen for VM changes and update the Model.
As mentioned in another answer your DataContext should be the VM (or property of it), not the model. Pointing at a DataModel makes it hard to separate concerns (e.g. for Test Driven Development).
Most other solutions put logic in ViewModels which is "not right", but I see the benefits of controllers overlooked all the time. Darn that MVVM acronym! :)
binding model to view directly only works if the model implement INotifyPropertyChanged interface. (eg. your Model generated by Entity Framework)
Model implement INotifyPropertyChanged
you can do this.
public interface IModel : INotifyPropertyChanged //just sample model
{
public string Title { get; set; }
}
public class ViewModel : NotificationObject //prism's ViewModel
{
private IModel model;
//construct
public ViewModel(IModel model)
{
this.model = model;
this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
}
private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Title")
{
//Do something if model has changed by external service.
RaisePropertyChanged(e.PropertyName);
}
}
//....more properties
}
ViewModel as DTO
if Model implements INotifyPropertyChanged(it depends) you may use it as DataContext in most cases. but in DDD most MVVM model will be considered as EntityObject not a real Domain's Model.
more efficient way is to use ViewModel as DTO
//Option 1.ViewModel act as DTO / expose some Model's property and responsible for UI logic.
public string Title
{
get
{
// some getter logic
return string.Format("{0}", this.model.Title);
}
set
{
// if(Validate(value)) add some setter logic
this.model.Title = value;
RaisePropertyChanged(() => Title);
}
}
//Option 2.expose the Model (have self validation and implement INotifyPropertyChanged).
public IModel Model
{
get { return this.model; }
set
{
this.model = value;
RaisePropertyChanged(() => Model);
}
}
both of ViewModel's properties above can be used for Binding while not breaking MVVM pattern (pattern != rule) it really depends.
One more thing..
ViewModel has dependency on Model. if Model can be changed by external service/environment. it's "global state" that make things complicate.
If your only problem is that changes from the server get immediately re-saved, why not do something like the following:
//WARNING: typed in SO window
public class ViewModel
{
private string _title;
public string Title
{
get { return _title; }
set
{
if (value != _title)
{
_title = value;
this.OnPropertyChanged("Title");
this.BeginSaveToServer();
}
}
}
public void UpdateTitleFromServer(string newTitle)
{
_title = newTitle;
this.OnPropertyChanged("Title"); //alert the view of the change
}
}
This code manually alerts the view of the property change from the server without going through the property setter and therefore without invoking the "save to server" code.
The reason you have this problem is because your model doesn't know whether it is dirty or not.
string Title {
set {
this._title = value;
this._isDirty = true; // ??!!
}
}}
The solution is to copy the server changes via a separate method:
public void CopyFromServer(Model serverCopy)
{
this._title = serverCopy.Title;
}

How to pass ViewModel to CodeActivity using WF4 with MVVM and WPF

I am trying to integrate my current WPF/MVVM application to Workflow Foundation 4.0.
Currently one of my ViewModel methods is invoking my sample CodeActivity sending it some parameters.
Inside of my CodeActivity execute method I need to call some methods from the calling ViewModel. I would like to know what the best approach is to do this. So far I have identified three possible ways:
Send my ViewModel instance as an input argument to my CodeActivity
Send my ViewModel instance through a Constructor in my CodeActivity like public MyCodeActivity(ViewModel vm)
Wrap my CodeActivity in a WorkflowApplication and send my ViewModel instance as an extension using SynchronizationContext
So far I have tested options 2 and 3 and they work well apparently.
What is the optimal way to do this to avoid any issues like thread synchronization problems or other?
Thanks in advance,
Edit:
Just to mention a possible scenario: If user picks value 'X' from a given dropdown list in my View I need to add object childA and childB to an ObservableCollection contained by a ParentObject exposed through a public property in my ViewModel. The logic to create the child objects and add them to the parent are in my ViewModel. But I want Workflow to contain the Business Rule itself.
Why does your CodeActivity need to know anything about a specific view model? I would look for another solution that allows your activity to maintain as much independence as possible. Two options I can think of off the top of my head:
Use an abstract class or interface so that your activity is not bound to a single viewmodel, i.e., InArgument<IViewModel>
Facilitate communication using an event aggregation pattern (if possible if WF4, not too sure on this yet?), i.e., give the activity what it needs to do it's job and let your view model listen for an event to receive updates from the activity
Without knowing the specifics of your application, I don't know which option would work best (or work at all), but I would avoid a direct connection between a given view model and a given CodeActivity.

Categories