I'm making the move from MVP to MVVM, and a little confused as to how best bind the ViewModel to the Model. I understand how we can leverage WPF's data binding infrastructure to route events between the View and ViewModel using ICommand and INotifyPropertyChanged interface, e.g., the View:
public class MyView
{
public MyView()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
and the ViewModel:
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel(){}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand MyCommand ...
}
This works great!
Now, typically with MVP I'd have my Presenter hold a reference to the Model via constructor injection, and raise events on the Model from the Presenter to update data in the Model. I tried the same approach with MVVM, but this requires the ViewModel to take the Model as a dependency in its constructor, which seems to make things a little messy with MVVM when using it straight out of the box without some form of IOC (with WPF at least).
So, my two questions are:
Is injecting the Model into the ViewModel the right approach, or should I be implementing INotifyPropertyChanged interface on the Model and making use of WPF's binding infrastructure?
To reap the benefits of MVVM, should you almost always implement it with IOC and a DI container, or better still Prism?
It is the "pure" MVVM approach: the View must depend only on the ViewModel. The ViewModel itself is a bridge between the View and Model.
The motivation — definition and responsibilities of the Model, View and ViewModel and also their relationships:
The Model, which provides a view-independent representation of your business entities. The design of the model is optimized for the logical relationships and operations between your business entities, regardless of how the data is presented in the user interface.
The View class which is the user interface. It displays information to the user and fires events in response to user interactions.
The ViewModel class, which is the bridge between the view and the model. Each View class has a corresponding ViewModel class. The ViewModel retrieves data from the Model and manipulates it into the format required by the View. It notifies the View if the underlying data in the model is changed, and it updates the data in the Model in response to UI events from the View.
-- Implementing the Model-View-ViewModel Pattern, MSDN.
Conclusion. Injecting the Model into the ViewModel seems to be the right approach. Also, instead of injecting Model it can be useful to inject:
the Model Factory to create the Model — lazy initialization;
the Service (Service Facade) to retrieve the Model — lazy loading.
As shown in the "MVVM Unleashed" book by Michael Brown, the following MVVM's potential benefits can be leveraged: maintainability, testability, "blendability", portability. At least, dependency injection (in the described case by using dependency injection container) allows a design to follow the Dependency Inversion Principle:
The principle of dependency inversion is at the root of many of the benefits claimed for object-oriented technology. Its proper application is necessary for the creation of reusable frameworks. It is also critically important for the construction of code that is resilient to change. And, since the abstractions and details are all isolated from each other, the code is much easier to maintain.
-- The Dependency Inversion Principle, Robert C. Martin, 1996.
As a result, such MVVM's benefits as the maintainability and testability seem to be improved when the Dependency Inversion Principle is followed. Dependency injection container is just a tool to follow the Principle.
Related
I need to send notification from ViewModel to View in MVVM WPF application. In most cases it will be simple MessageBox on View side. Is it unacceptable violation of MVVM pattern to use types like System.Windows.MessageBoxResult or System.Windows.MessageBoxImage in ViewModel (in this case VM must reference UI-specific libraries)?
I need to pass title, message and notification type from VM and by creating custom enumerations I am in fact copying existing functionality from .NET Framework.
You don't need notification mechanism. That's one option. Another is using simple service class:
public class ViewModel
{
IDialogService _dialogService; //ctor injection or use service locator
public void CommandExecute()
{
_dialogService.ShowMessageBox(...);
}
}
public interface IDialogService
{
bool? ShowMessageBox(params....);
}
public class DialogService : IDialogService
{
public bool? ShowDialog(params...)
{
MessageBox.Show(params...);
}
}
I find this approach more straightforward, easier to understand and easier to debug. Messaging may easily turn into memory leak and in this case I don't see any benefit over my approach.
EDIT:
Will you use custom enum in ShowMessageBox parameters, or will you use
System.Windows.MessageBoxImage?
First of all, ViewModels belong to presentation layer. It is OK to use enums like System.Windows.MessageBoxImage in ViewModel.
In MVVM, ViewModels are separated from Views because of following reasons:
ViewModels expose data and logic from Model in such way that is easily consumable from Views (e.g DataBinding)
ViewModels are easier testable
ViewModels provides better design time support (Blendability, test data)
ViewModels separates application logic from the actual presentation markup which makes it easier to understand (readbility)
Does using enum like System.Windows.MessageBoxImage breaks any of the points above? The answer is no.
If you wanted to reuse IDialogService and your ViewModels on multiple platforms, for example WPF, UWP and Xamarin, then you need to create your own enum, because it may not exist on all platforms. The golden rule is: don't add another layer of abstraction if you don't need it.
You could have the view implement an interface, say INotificationService and then pass the view to the view model constructor. That won't violate MVVM, and you will still be able to bind the view model to the view using the DataContext property on the view.
I decided to keep ViewModel as clean of UI (View) stuff as possible, so I will create custom enumeration inspired by MessageBox and tailored exactly to my needs.
Following WPF MvvmFoundation, linking the View with the ViewModel has many choices like described on http://www.paulstovell.com/mvvm-instantiation-approaches.
However their example has nothing about how to link the ViewModel with the Model.
Traditionally I created the model first and then one or more views that render it. It seems that MVVM pushes people to create the View, which creates the ViewModel, which create the Model. I hope it's not the case as wiring a complex business model with various ModelView can else be tough.
How do you instantiate your business model classes in MVVM and link them with your ViewModels?
I normally pass Model objects as constructor params to VM. I use App class as the controller which will initialize MainWindow, MainWindowViewModel with the main model. There after the MainWindowViewModel takes care of initializing other VMs with appropriate model objects.
private void Application_Startup(object sender, StartupEventArgs e)
{
mainWindow = new MainWindow();
mainWindow.DataContext = new MainWindowViewModel(new Model());
mainWindow.Show();
}
You create your BusinessModel classes inside your ViewModel.
So in your CustomerViewModel you would say this.CurrentCustomer = new CustomerModel(), and your CustomerView would bind to the CurrentCustomer property on the ViewModel
If you are interested, I wrote up a simple sample using MVVM as an example of how the View, Model, and ViewModel interact.
I use dependency injection/MEF to do this. Just export all of my model classes all the way down the chain, and have them imported for me automatically into the ViewModel constructor.
I take a variety of different approaches depending on the situation. I've found that when it comes to getting this data linked, one size does not fit all.
For simple cases, I will have the ViewModel and the Model be the same thing. Obviously not that good for all cases, but sometimes there is just no need to go the extra mile to split the M from the VM. (Great for cases where you have, say, listbox items that have scant information)
Sometimes, especially when the model is a chunk of code you don't have access to (written by another developer) it is easy to subclass the model, and add all of your VM things (observable properties, etc.) on to it.
Lastly, I will use the approach that is mentioned by Souvik. Construct the VM with the model information that you want to use as a parameter, or allow it to be passed in otherwise. This is probably the most common approach for my larger and more complex Model / ViewModel relationships.
I am auto-passing IRepository instance to VM constructor using IoC container and everything VM needs to do with models is done via this repository. Repository is class which: Create, read, update and delete data. When I need to show some view (window), I use IViewService.ShowDialog(viewModel As ViewModelBase). In implementation of IViewService, there are views registered with VMs, so VMs only need to know other VMs and not their views (like "Show me view for this view model").
I can't see it
http://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx
How do you want to separate concerns then if controller is mixed with view-model ? controller is not reduced to just databinding there is also commands.
I mean if MVVM also has the responsability of a controller then this design violates the principle of Separation of concerns. Maintaining state of the view and orchestrating logics of View and Model are clearly 2 big tasks that should be separate and that's the reason behind C of MVC
So what if I want to have a separate controller: how hard it would be as WPF and silverlight makes GUI load first without allowing invisible class to load first like controller and then manage the view and model ?
Aren't you looking at this in with respect to the MVC pattern rather than looking at this in a separation of concerns angle? The way I see it, your question compares MVVM to MVC.
There are different approaches to MVVM: View-First, ViewModel first and Marriage type. I marriage type you can have another class that marriages these the View and the ViewModel. The said class loads first before anything, instanciates View and ViewModel then marriages both.
public class SomeScreen : ScreenBase, IScreen
{
[Import(typeof(ISomeViewModel))]
public IViewModel ViewModel
{
get { return this.GetPropertyValue(ApplicationProperties.ViewModel); }
set {
this.SetPropertyValue(ApplicationProperties.ViewModel, value);
RaisePropertyChanged(ApplicationProperties.ViewModel);
}
}
#region Constructor
public MainScreen()
{
CompositionInitializer.SatisfyImports(this);
}
#endregion
#region Methods
public override IView GetViewToDisplay()
{
IView view = new MainView();
//Or maybe have a mechanism here based on settings which view to pair up with this.
view.ViewModel = this.ViewModel;
this.ViewModel.View = view;
return view;
}
#endregion
}
With this example, there would be a total separation between them and no dependencies because of the interfaces and you can add a whole lot of functionalities to the screen/controller too.
I am new in MVVM and WPF. so be easy with me.
I have a model (model A) in MVVM, in the ViewModel I have a collection.
The collection is present in the View as ListView.
I have another model (model B - not ui model) that need to do something every time that the listview is changing.
How can I alert model B on the selection change? What will be the right way?
By event that model A (ViewModel) will fire, and model B will catch?
By attached property of model A?
By notify property change?
By sending relay commands from model B to model A?
Use Publish /Subscriber pattern
like used in the EventAggregator
http://msdn.microsoft.com/en-us/library/ff647984.aspx
Or in the Messenger
.http://geekswithblogs.net/lbugnion/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx
usualy MVVM frameworks ship mechanism for this build in.
Personally I would send the commands from VM to VM and make them update the Model
hope this helps
I would either
Expose an event in ViewModel A that ViewModel B can subscribe to. I would then raise that event anytime the selection changes.
Leverage INotifyPropertyChanged for notification to ViewModel B
I prefer option 1 because it makes it more obvious what you're trying to do. Plus it's more efficient (you don't have code smell of filtering on which property changed and then doing some action.)
IMHO I think relay commands should only be used as an interface between a view and a viewmodel to aid in a separation of concerns. But when you're programming from a class to a class, just use standard OOP conventions.
so pseudo code would probably look like this:
public class ViewModelA
{
public event EventHandler SelectedObjectChanged;
public IList<MyObject> ObjectList {get;set;}
public MyObject _SelectedObject;
public MyObject SelectedObject
{
get { return _SelectedObject;}
set
{
_SelectedObject = value;
if (SelectedObjectChanged != null)
SelectedObjectChanged(value);
}
}
}
I have been reading about MVVM pattern from various sources like MSDN:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
In that article it says: Unlike the Presenter in MVP, a ViewModel does not need a reference to a view.
If the View (XAML) assumes it's DataContext is the ViewModel then where in the code is the following line:
view.DataContext = viewModel;
The ViewModel doesn't know anything about the view so it cannot set the datacontext. If I give the ViewModel the reference do I break the MVVM pattern? My other choice is to have some kind of Builder or extra Presenter whose only job is to wire the whole thing (wait for the loaded event of the View, set the DataContext).
I know different view's can share the same DataContext (e.g. set the DataContext only for the mainwindow and others will see it) but in many cases that is not possible at all nor even feasible.
This is a great question that has many answers. It all depends on how you want to architect your application. For instance, I use dependency injection to create my IViewModel, which in turn creates my IView and my IViewModel runs an IView.SetViewModel(this) on the constructor.
Other people may wish to use a more Blendable method by setting the DataContext in the Xaml:
<UserControl.DataContext>
<ns:CrazyViewModel />
</UserControl.DataContext>
Sometimes the DataContext can be implied so it is set by the framework, like in the instance of a DataTemplate used by an ItemsControl. This is also pretty common in desktop WPF because it supports typed DataTemplates.
So there really isn't a wrong way to set the DataContext, just as long as what you have separates concerns, is maintainable and is also easily testable.
Shawn Wildermuth has a great post about whether the View or ViewModel comes first:
http://wildermuth.com/2009/05/22/Which_came_first_the_View_or_the_Model
I like, and use, his marriage concept where a 3rd party class creates both the view and viewmodel, and then associates the two. It's worked well for me.
I use MVVM a lot in with Prism. In Prism I use Unity for dependecy injection. Therefore I have an interface for every class registered with Unity including the View.
The IView interface has a method like this:
void SetViewModel(object viewModel);
The ViewModel calls this method at the end of its constructor, passing itself as a parameter:
public ViewModel(IView view, ...)
{
...
this._view=view;
this._view.SetViewModel(this);
}
In the View.xaml.cs the IView interface is implemented. This will be the only code I add to the codebehind of the view:
public partial class View:UserControl, IView
{
public View()
{
...
}
public SetViewModel(object viewModel)
{
this.DataContext = viewModel;
}
}
As for my own usage, the ViewModel doesn't know the View, or any interface on the View. And most of time, the View doesn't know its ViewModel, even if it is less important. The VM is just transprted by the DataContext.
This ensures that the VM and V will remain highly independant. Links are established thoughout bindings, commanding, Behaviors, Triggers & so on. Even if VM is often highly related to a given view, I try to make it as generic as possible, so that I can switch the corresponding View, and / or adapt the View behavior without needing to update the VM, except if the architectural link between V and M is impacted !