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 !
Related
I am trying to find the best practice for creating view models and services (service just talks to the server and return data back to view model). I have seen 2 different approaches.
Using view model locator
Using behaviors (I am not sure if this is good approach)
For the second approach, you define a behavior on UserControl and on attach event you create an instance of view model and an instance of service and put them all together.
protected override void OnAttached()
{
var service = Activator.CreateInstance(ServiceType)
var viewModel = Activator.CreateInstance(ModelType);
base.AssociatedObject.DataContext = viewModel;
base.OnAttached();
}
and in your usercontrol xaml
<i:Interaction.Behaviors>
<be:ViewModelBehavior ViewModelType="{x:Type vm:ViewModel1}" ServiceType="{x:Type serv:Service1}"/>
</i:Interaction.Behaviors>
Is this a good use of behaviors, or I should just use viewmodel locator pattern.
Your behavior has one significant disadvantage - in each usercontrol you have to specify the behavior, ViewModelType (and ServiceType as well).
You can do following:
<UserControl x:Class="MyApp.HomePage" ....
local:ViewModelLocator.AutoWireViewModel="True">
...
</UserControl>
When you set the attached property to true, ViewModelLocator will create the viewmodel instance and assign it to the usercontrol's datacontext. The ViewModelLocatator uses naming convention to determine type of viewmodel. In this case it could be HomePageViewModel, because the view type is HomePage.
This approach is used by PRISM ViewModelLocator from Prism.Mvvm library, but I recommend you to write your own, since it's quite easy.
It is basically similar to your ViewModelBehavior, but the re are two differences:
The behavior is implemented as attached property. It allows you to specify the behavior in Style, so it will be applied to any usercontrol that uses this style. You cannot specify Interaction.Behaviors in styles.
It uses naming convention instead of explicitly set ViewModelType
Regarding the service, that should be passed as a parameter to viewmodel: You can use IoC pattern. This is pseudocode, that describes the pattern:
public class MyViewModel(IMyService service) {...}
//at application startup you setup the IoC container:
IoC.Setup<IMyService>(new MyService());
//later
var viewModel = IoC.GetInstance<MyViewModel>(); //MyService will be passed as to ctor
I am pretty new to WPF and right now I am trying to get used to the MVVM pattern. Right now I have a simple application in which I have a collection of ViewModels that I display in a grid. When I doubleclick on the row in the grid I want to show a details View of the ViewModel.
The problem I am having right now is that I already have a fully instanced ViewModel, but I can't seem to pass it into the view. When I try to load that View it turns up empty. I already found out that this is due to the fact that when a View gets loaded it creates it's own instance of the backing ViewModel. So obviously I need to get around this behaviour and somehow pass the instanced ViewModel into the View when it is created. I could use a constructor in the View that takes a ViewModel and set the datasource in there. However, taking this approach but would mean that I need to construct the View in the ViewModel and thus making the ViewModel aware of the View. This I something I would like to avoid since I am trying to uphold the MVVM pattern.
So what should I do in this case? Should I just break the MVVM pattern or are there some nice and clean sollutions for this that fit in the MVVM pattern?
There are many ways of passing a view model to a view, as you call it, or setting a view model as the DataContext of either a Window or UserControl, as others may call it. The simplest is just this:
In a view constructor:
public partial class SomeView
{
InitializeComponent();
DataContext = new SomeViewModel();
}
A more MVVM way might be to define DataTemplates in App.xaml for each view model that defines which view each will use:
<DataTemplate DataType="{x:Type YourViewModelsPrefix:YourViewModel">
<YourViewsPrefix:YourView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type YourViewModelsPrefix:AnotherViewModel">
<YourViewsPrefix:AnotherView />
</DataTemplate>
Now whenever the Framework comes across an instance of these view model classes, it will render the associated view. You can display them by having a property of the type of your view model using a ContentControl like this:
<ContentControl Content="{Binding YourViewModelProperty}" />
Or even in a collection like this:
<ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
"Should I just break the MVVM pattern?"
Well, please consider to learn more about the pattern, to know what it is to "break it". The main purpose of this pattern is to keep responsability clear, thus to obtain testable and maintainable code. There are a lot of ressource for that as show in this question:
MVVM: Tutorial from start to finish?
Anyway to be more specific about your question, what you are looking for is how to set the DataContext.
"somehow pass the instanced ViewModel into the View when it is created"
Yes, you get it, if you assign the dataContext with a viewModel in the constructor of your view, it could work but it it is acceptable only if the viewModel has the responsability to create the view (which could be acceptable in really few situation). You could even write something like that to directly set DataContext from outside your view:
var l_window = new MyView { DataContext = new MyViewModel() };
l_window.Show();
Of course the main drawback is that this code is not testable. If you would like to test it you should use a mockable service to manage the view creation.
A more common solution is to inject the dataContext with an IOC container (like prism). You create all required ViewModel when the software started and you store them in this IOC container. Then, when the view is created, you ask this container to get you an instance of your viewModel.
An example could be: export your viewModel in PRISM:
[Export]
public class MyViewModel {...}
And then Import it in your view:
[Import]
private MyViewModel ViewModel
{
set { this.DataContext = value; }
get { return this.DataContext as MyViewModel; }
}
Hope it helps.
I agree with #Sheridan's answer and would only like to add another way to instantiate a view with a view model: you could use the Factory Pattern, maybe like this:
public class ViewFactory
{
public UIElement Create(object context)
{
// Create the view model
// You can pass in various information by parameters
// as I do with context (Constructor Injection)
var viewModel = new ViewModel(context);
// Create the view and set the view model as data context
var view = new View { DataContext = viewModel };
return view;
}
}
You can call this factory from within a method of your view model and then assign it to e.g. a property that is data bound to the UI. This allows for a bit more flexibility - but #Sheridan's solution is also fine.
Can I use UnityContainer in View's codebehind when I want to write good MVVM program?
this.DataContext = uc.Resolve<MainViewModel>();
If you're asking if you can, yes.
If you're asking if you should, the answer is still yes.
ServiceLocator is an anti-pattern, you shouldn't be using it. The reason it's an anti-pattern is because it allows for objects to be resolved inside a class at any time, reducing the usefulness of your DI and making your code harder to unit test.
My suggestion would be to do one of the following:
a) Inject the viewmodel into the view through it's constructor. Resolve the view using Unity so that it resolves all the views dependencies (the view model) for you.
So:
public partial class View:UserControl,IViewFoo
{
public View(IViewModel viewModel)
{
DataContext=viewModel;
}
var view=_container.Resolve();
}
b)
Use an attached property to inject the viewmodel into the DataContext for you. MEFEDMVVM and MVVMLite both do this (look them up on Codeplex)
c)
Follow a convention-based approach where the viewmodel gets assigned to the view based on them having compatible names (MainView.cs and MainViewModel.cs). Caliburn Micro does this and is very nice to use. This can also be found on CodePlex.
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'm just getting started with the MVVM pattern in WPF and I decided that the most elegant way to structure my code was injecting the view-model in to the view's constructor.
This is all well and good, but ReSharper gives a warning in the XAML that my view doesn't have a default constructor. I'm assuming that this is so that I can construct my view in XAML if required, but that's only a guess.
What am I giving up by requiring my view to take a view-model in the constructor?
Edit: My view constructor looks like this:
public ExampleView(ExampleViewModel viewModel)
{
if (viewModel == null) throw new ArgumentNullException("viewModel");
DataContext = viewModel;
}
Answer: I settled on the following set up, where the DesignTime namespace contains mocked up versions of the ViewModel for testing and design time support.
ExampleView.xaml.cs
public ExampleView()
{
InitializeComponent();
}
public ExampleView(IExampleViewModel viewModel)
: this()
{
DataContext = viewModel;
}
ExampleView.xaml
<UserControl
x:Class="Wpf.Examples.ExampleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DesignTime="clr-namespace:Wpf.Examples.DesignTime">
<UserControl.DataContext>
<DesignTime:ExampleViewModel/>
</UserControl.DataContext>
</UserControl>
As you correctly recognized, requiring a non-default constructor will deny you using that control from XAML. That also means no more design-support and your designers will probably hate you. Finally you break all sorts of nice data binding scenarios. Like using the control as an ItemTemplate.
As a remedy for the missing design support, I would suggest implementing a default constructor which creates a mocked view-model which doesn't need any infrastructure. That way you can support design mode very elegantly and putting the view in a XAML file (e.g. for testing) will do something sensible.
As a remedy for the missing data binding support, you should ponder whether it might be better to consume the view model via the DataContext of your WPF control. This is common in WPF and---as far as I can tell---the intended way to pass the model to the view in WPF.
Assuming that you don't need designer support then I see no reasons.
To keep designer support you need a default constructor. When you define your own constructor you basically loose the autogenerated default constructor. Just create an explicit default constructor and you should be fine.