WPF + MvvM + Prism - wpf

I am new in the Wpf & Mvvm world , but I have found a couple of examples and just found that there is some different way to instantiate the model. I would like to know the best/correct way to do it. both ways are using Unity
What I've foud:
var navigatorView = new MainView();
navigatorView.DataContext = m_Container.Resolve<INavigatorViewModel>();
m_RegionManager.Regions["NavigatorRegion"].Add(navigatorView);
What I did:
var navigatorView = m_Container.Resolve<MainView>;
m_RegionManager.Regions["NavigatorRegion"].Add(navigatorView);
and I changed the constructor to receive viewmodel so I can point the datacontext to it:
public MainView(NavigatorViewModel navigatorViewModel)
{
this.DataContext = navigatorViewModel;
}
Other examples I've found another way like:
...vm = new viewmodel
...m = new model
v.model = vm;
get/set DataContext
cheers

I like Igor's suggestion, but without the viewmodel having knowledge of the view. I prefer my dependencies to go one direction (View -> ViewModel -> Model).
What I do is ViewModel-First and just DataTemplate the viewmodel. So I do this:
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
region.Add(mainViewModel, "MainView");
region.Activate(mainViewModel);
With the addition of the ViewModel -> View mapping done with a WPF datatemplate (I don't think this approach is possible with Silverlight, though)
App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type viewModels:MainViewModel}">
<views:MainView />
</DataTemplate>
</Application.Resources>
That's it! I love this approach. I like the way it feels like magic. It also has the following advantages:
Don't have to modify constructors to suit the mapping
Don't have to register type for IMyViewModel in the container... you can work with concrete types. I like to keep my registrations to application services like IViewRegistry or ILogger... those kinds of things
You can change the mapping using resources scoped to a particular view that a region is in (this is nice if you want to reuse your ViewModels but want them to look different in different areas of the application

What you got there makes sense and in both cases is a View-first approach to creating a viewmodel. I.e. the view creates the ViewModel. In the original example the viewmodel is created outside of the view (and is sometimes referred to as marriage pattern), but as far as I am concerned that's the same thing - creation of the view creates the ViewModel.
If this suits your needs stick with it. Another approach you might look into is ViewModel first where the viewmodel takes a dependency on the view like so:
//In the bare-bones(i.e. no WPF dependencies) common interface assembly
interfac IView {
void ApplyViewModel(object viewmodel);
}
interface IMainView : IView {
//this interface can actually be empty.
//It's only used to map to implementation.
}
//In the ViewModel assembly
class MainViewModel {
public MainViewModel(IMainView view) {
view.ApplyViewModel(this);
}
}
public partial class MainView : UserControl, IMainView {
void ApplyViewModel(object viewmodel){
DataContext = viewmodel;
}
}
Then you can inject this view like so:
IRegion region = regionManager.Regions["MainRegion"];
//This might look strange as we are resolving the class to itself, not an interface to the class
//This is OK, we want to take advantage of the DI container
//to resolve the viewmodel's dependencies for us,
//not just to resolve an interface to the class.
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
region.Add(mainViewModel.View, "MainView");
region.Activate(ordersView.View);

Related

WPF MVVM and passing viewmodels to a view

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.

How should I populate the ViewModel in WPF?

I'm new to WPF and I'm writing a simple test app to familiarize myself with it. My test app will detect all joysticks I have attached to my computer and display information about it. So far, I have this ViewModel:
public class JoystickViewModel
{
public ObservableCollection<Joystick> Joysticks { get; set; }
public JoystickViewModel()
{
GetAttachedJoysticks();
}
private void GetAttachedJoysticks()
{
// populate Joysticks collection by using SlimDX
}
}
And this is my codebehind for my MainWindow.xaml:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new JoystickViewModel();
}
}
And my XAML for MainWindow:
<Window ...>
<Grid>
<ComboBox ItemsSource="{Binding Joysticks}"
DisplayMemberPath="Information.ProductName"/>
</Grid>
</Window>
I followed a tutorial that also populated the ViewModel in its constructor.
My question is, how should I populate the ViewModel? It seems sort of weird to me that I'm population the collection in the ViewModel constructor. Should this logic be in MainWindow's codebehind instead? Or somewhere else altogether? The end goal is to not only have this collection populated, but also updated periodically to reflect the current state (user plugged in new joystick, unplugged existing one, etc...).
The MainWindow code behind is definitively not the place where "business" logic should occur, as the View should be kept as simple as possible.
Keep your fetch/update logic inside of your viewmodel, this way you can test it easily and independently.
From a learning perspective, it's important to keep concerns separated :
the View is bound to the ViewModel, and has no intelligence
the ViewModel has knowledge on how to get the Model
the Model represents the data
In your case, the VM knowledge is at the moment a call inside it's constructor. Later you can change this to call some IJoystickDataService interface, and wire everything using a MVVM framework.
I would have your JoySticks observable collection property (and the code that populates it) in a Model class. The viewmodel simply exposes this same property to the view for binding. The vm should be as thin as possible - ideally just exposing properties that are in the model for binding and not doing any kind of 'business' logic (i.e. populating joystick info as in your case).

Prism MVVM - How to pass an IEventAggregator to my ViewModel

recently I started working with Prism in Silverlight. I want to use the EventAggregator to Subscribe and Publish events between two ViewModels. As I saw on some guides, the ViewModel's ctor should accept IEventAggregator as a parameter. I can't find out how to do this hence my View always wants to initialize the ViewModel with a parameterless ctor.
My ViewModel ctor:
MyViewModel(IEventAggregator eventAggregator)
{
// get the event....
}
My View:
<UserControl ....>
<UserControl.Resources>
<ViewModels:MyViewModel x:Key="MyViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MyViewModel}}">
....
<Grid/>
</UserControl>
I can instantiate the ViewModel in the ctor of the View, and then assign it to its DataContext, but then I must have an IEventAggregator in my View, which I also cannot get. but this is probably not the correct way to pass an IEventAggregator (or any other object! - IUnityContainer for example) to the ViewModel.
Can someone tell me what I'm doing wrong?
You have to resolve your dependency via unity. Have a look at the prism MVVM examples and the ui composition. There the view does not create the view model, but it is exactly the other way round. The view model gets the view injected via constructor injection. The view model sets itself as view model for the view:
public interface IView
{
IViewModel ViewModel{get;set;}
}
public interface IViewModel { }
public View:UserControl, IView
{
public IViewModel ViewModel
{
get{return DataContext as IViewModel;}
set{DataContext = value;}
}
}
public ViewModel:IViewModel
{
public ViewModel(IView view, IEventAggregator eventAggregator)
{
view.ViewModel = this;
//get the event...
}
}
Using this approach you have to register the view model and the view to unity. Afterwards you only have to resolve the view model, the view is injected by the container.
To get the view to the right place on the user interface you have to register the view to a region using the RegionManager. When this is all set up, creating a new view model instance results in adding the view into the registered region so that it shows up on the user interface.
Other than having the ViewModel hook itself into the data context of the view (which I don't like at all), there are two other options that I can think of in Silverlight.
Utilize the ServiceLocator pattern to allow your static resources to create themselves via the container. MVVMLight has a fairly good pattern for this.
Use a framework like Caliburn.Micro, which plugs in a nice set of conventions that will wire up many things based on naming conventions, including bindings and viewmodels.
Maybe you've solved it already but
http://www.emileinarsson.se/silverlight-4-mvvm-prism-unity-dependency-injection/
this post explains how to use Unity in a MVVM environment.

MVVM: Giving every modular part it's own XAML class

I was thinking about doing this instead defining lot's of DataTemplates. This would mean that if I had a collection of things the ItemsControl itself would have a XAML class and the objects would have one too.
This is something that already happens when the objects are proper ViewModels containing models and logic but if it's just a Command for example. A dynamic group of commands perhaps.
Pros: I could use the designer to help me define the look of the object as I don't have blend and it would be easier to find and change those parts if needed.
Cons: More XAML classes.
Would you talk me into this or out of this.
EXAMPLE
I have buttons all around the app so I define a ButtonViewModel which has a display name and a ICommand Property. I would also define a DataTemplate or UserControl for this object which would basically be a button with Command binding and text/content binding to the display name. I could also define it's look and such.
Then in ViewModels that should include buttons I would add these buttons as part of the class and bind to them inside the view.
public class ButtonViewModel : ViewModelBase
{
private string _displayName;
public string DisplayName
{
get
{
return _displayName;
}
set
{
_displayName = value;
RaisePropertyChanged("DisplayName");
}
}
private ICommand _command;
public ICommand command
{
get
{
return _command;
}
protected set
{
_command = value;
RaisePropertyChanged("Command");
}
}
public ButtonViewModel(ICommand command, string displayName)
{
Command = command;
DisplayName = displayName;
}
}
ViewModel using the ButtonViewModel
public class SomeViewModel : ViewModelBase
{
//some functionality
//It could be done as a collection or just seperate ButtonViewModel properties
public ObservableCollection<ButtonViewModel> Buttons { get; set; }
//Somewhere where it makes sense, here in the constructer for the heck of it
public SomeViewModel()
{
Buttons.Add(new ButtonViewModel(new RelayCommand(Save, canSave), "Save"));
Buttons.Add(new ButtonViewModel(new RelayCommand(Edit, canEdit), "Edit"));
Buttons.Add(new ButtonViewModel(new RelayCommand(New, canAddNew), "New"));
}
}
The buttons view:
<UserControl x:Class="WpfApplication1.ButtonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="60" Width="90">
<Button Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}">
<!-- Some really cool design for your button -->
</Button>
</UserControl>
You could also define a specific ItemsControl to hold a collection of buttons, even going so far as to define a ViewModel for said itemscontrol.
I once learned that if you can encapsulate some item in a class you should. Is this just crazy talk?
I'm not quite sure what you're asking, but it sounds as if you are taking a view first approach, which can get very complex in everything but the simplest of apps. Have you considered using an MVVM framework such as Caliburn.Micro?
Using a view model first approach, you can instantiate your view model, and then use Caliburn.Micro to locate your view (via convention), and automatically bind the two up.
Caliburn.Micro will also do view composition, so for example, if you have a collection of view models on your parent view model, and you expose that collection from a property with the same name as a ListBox on your view, then Caliburn.Micro will automatically use the corresponding view for each item in the collection, and bind up each items view model with the view.
You can also use different views over the same view model, and Actions are used to invoke verbs on your view models from view controls, rather than commanding, which allows for much richer imagining of UIs.

Who sets DataContext in Silverlight MVVM

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 !

Resources