WPF - Using behaviors for instantiating view model and services - wpf

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

Related

WPF+MVVM: How to use plain old ViewModelBase when DependencyProperty is needed

I am using a 3rd party WPF control whose MVVM support relies on dependency properties on the VM it is bound to. The sample that comes with the control uses a ViewModelBase class derived from DependencyObject so all is well.
My ViewModelBase implements INotifyPropertyChanged and for various reasons it is unrealistic to change it to DependencyObject.
My question is how do I use my ViewModels with this WPF control? I guess what I need is something like "embedding a dependencyobject" or "plugging dependency properties" in a plain old ViewModel.
By the way my MVVM application is interface based, i.e. everywhere SomeViewModel is ISomeViewModel.
In general, a properly designed control shouldn't require binding to a DependencyProperty, as a DP can bind to any property without issue. As such, I'd revisit whether this is truly a bug in the control implementation first, and correct that.
However, if you must do this, realize you're going to violate MVVM - using DependencyObject within a ViewModel is, by its very nature, injecting view specific framework elements into the VM. Once you decide you're okay with doing this, you can always have your ViewModel expose a DependencyObject as a property, and bind to a DependencyProperty defined on that DependencyObject instead of directly to your VM's property.

Blend Behaviours - can you bind to their properties?

I am currently migrating a number of attached behaviours I have created to Blend Behaviours so that they support drag and drop within Expression Blend. I have noticed that authors of Blend behaviours tend to define the behaviour properties as dependency properties.
I have created a behaviour, TiltBehaviour, which exposes a public dependency property, TiltFactor, of type double. Within Expression Blend I can set the value of this property, however, the option to add a "Data Binding ..." is grayed out:
I have also noticed that Behaviors extend DependencyObject, therefore they do not have a DataContext and therefore cannot inherit the DataContext of the element to which they are attached. This feels like a real weakness to me!
So, the bottom-line is, if I cannot set a binding to my behaviors dependency property in Blend, and it does not inherit a DataContext, why bother using dependency properties at all? I could just use CLR properties instead.
Blend behaviors would be almost useless unless they supported binding! I recreated your tilt behavior and it supports binding in Blend 4 with no problems so I don't know exactly where you went wrong. Perhaps you can reproduce my simple example and then infer what's wrong with your setup.
Here's the (non-functional) tilt behavior with dependency property:
public class TiltBehavior : Behavior<FrameworkElement>
{
public double TiltFactor
{
get { return (double)GetValue(TiltFactorProperty); }
set { SetValue(TiltFactorProperty, value); }
}
public static readonly DependencyProperty TiltFactorProperty =
DependencyProperty.Register("TiltFactor", typeof(double), typeof(TiltBehavior), new UIPropertyMetadata(0.0));
}
Then just create a new window and drop the behavior onto the grid and Blend creates this:
<Grid>
<i:Interaction.Behaviors>
<local:TiltBehavior/>
</i:Interaction.Behaviors>
</Grid>
and the Blend "Data Binding..." option is available in the properties tab.
I tested this with both WPF and Silverlight projects. The built-in behaviors, triggers and actions all support binding by virtue of using being dependency properties and all the Blend samples use binding heavily and so this has to work.
In fact you can just drop a built-in behavior like FluidMoveBehavior onto your grid and check that Duration, which is a dependency property, supports binding. If that doesn't work, I have no idea what's going on!
Let's consider then how binding works for these strange beasts called behaviors.
As WPF or Silverlight programmers we are very familiar with binding for things like FrameworkElement. It has a property called DataContext that we can manipulate to control the default binding source and that property is inherited by nested elements when we don't override it.
But behaviors (and triggers and actions) are not of type FrameworkElement. They are ultimately derived from DependencyObject, as we might expect. But while we can using binding on any class derived from DependencyObject, our familiar DataContext is missing at this low-level and so the binding has to supply the source. That's not very convenient.
So behaviors are derived (on WPF anyway) from Animatable and Animatable is derived from Freezable. The Freezable class is where the simplicity of dependency objects intersects with the complexity of framework elements. The Freezable class is also the base class for more familiar things like brushes and image sources. These classes don't need the full complexity of a framework element, but they want to participate, in a limited way with the elements that they are associated with.
Through a complicated magical process, Freezable instances acquire an inheritance context: the framework element they are most closely associated with, and when a default binding is used (one without a source), the Freezable uses the DataContext of it's associated element instead.
In fact as you learn about behaviors the AssociatedObject is a central concept; for a behavior it is the thing that the behavior is attached to. But the important point is that all Freezable objects can use the DataContext of their AssociatedObject by proxy.
All this magic is what Josh Smith calls the:
Hillberg Freezable Trick
And so all this leads up to saying that due to the Hillberg Freezable Trick, Blend behaviors support binding using the data context of their associated element as the default source. As a result, bindings for behaviors seem to "just work" without any effort on our part. Behaviors are a thousand times more useful because of this.
Edit: dain is correct you can still bind to the DataContext which is created artificially, how often have you seen people bind to a SolidColorBrush.Color? It also works even though SolidColorBrush inherits from DependencyObject and hence has no DataContext.
See this blog post on the inheritance context.
The thing is that since the behaviours are attached, they do not appear in the logical tree and hence would not inherit a DataContext anyway.

What is a ViewModelLocator and what are its pros/cons compared to DataTemplates?

Can someone give me a quick summary of what a ViewModelLocator is, how it works, and what the pros/cons are for using it compared to DataTemplates?
I have tried finding info on Google but there seems to be many different implementations of it and no striaght list as to what it is and the pros/cons of using it.
Intro
In MVVM the usual practice is to have the Views find their ViewModels by resolving them from a dependency injection (DI) container. This happens automatically when the container is asked to provide (resolve) an instance of the View class. The container injects the ViewModel into the View by calling a constructor of the View which accepts a ViewModel parameter; this scheme is called inversion of control (IoC).
Benefits of DI
The main benefit here is that the container can be configured at run time with instructions on how to resolve the types that we request from it. This allows for greater testability by instructing it to resolve the types (Views and ViewModels) we use when our application actually runs, but instructing it differently when running the unit tests for the application. In the latter case the application will not even have a UI (it's not running; just the tests are) so the container will resolve mocks in place of the "normal" types used when the application runs.
Problems stemming from DI
So far we have seen that the DI approach allows easy testability for the application by adding an abstraction layer over the creation of application components. There is one problem with this approach: it doesn't play well with visual designers such as Microsoft Expression Blend.
The problem is that in both normal application runs and unit test runs, someone has to set up the container with instructions on what types to resolve; additionally, someone has to ask the container to resolve the Views so that the ViewModels can be injected into them.
However, in design time there is no code of ours running. The designer attempts to use reflection to create instances of our Views, which means that:
If the View constructor requires a ViewModel instance the designer won't be able to instantiate the View at all -- it will error out in some controlled manner
If the View has a parameterless constructor the View will be instantiated, but its DataContext will be null so we 'll get an "empty" view in the designer -- which is not very useful
Enter ViewModelLocator
The ViewModelLocator is an additional abstraction used like this:
The View itself instantiates a ViewModelLocator as part of its resources and databinds its DataContext to the ViewModel property of the locator
The locator somehow detects if we are in design mode
If not in design mode, the locator returns a ViewModel that it resolves from the DI container, as explained above
If in design mode, the locator returns a fixed "dummy" ViewModel using its own logic (remember: there is no container in design time!); this ViewModel typically comes prepopulated with dummy data
Of course this means that the View must have a parameterless constructor to begin with (otherwise the designer won't be able to instantiate it).
Summary
ViewModelLocator is an idiom that lets you keep the benefits of DI in your MVVM application while also allowing your code to play well with visual designers. This is sometimes called the "blendability" of your application (referring to Expression Blend).
After digesting the above, see a practical example here.
Finally, using data templates is not an alternative to using ViewModelLocator, but an alternative to using explicit View/ViewModel pairs for parts of your UI. Often you may find that there's no need to define a View for a ViewModel because you can use a data template instead.
An example implementation of #Jon's answer
I have a view model locator class. Each property is going to be an instance of the view model that I'm going to allocate on my view. I can check if the code is running in design mode or not using DesignerProperties.GetIsInDesignMode. This allows me to use a mock model during designing time and the real object when I'm running the application.
public class ViewModelLocator
{
private DependencyObject dummy = new DependencyObject();
public IMainViewModel MainViewModel
{
get
{
if (IsInDesignMode())
{
return new MockMainViewModel();
}
return MyIoC.Container.GetExportedValue<IMainViewModel>();
}
}
// returns true if editing .xaml file in VS for example
private bool IsInDesignMode()
{
return DesignerProperties.GetIsInDesignMode(dummy);
}
}
And to use it I can add my locator to App.xaml resources:
xmlns:core="clr-namespace:MyViewModelLocatorNamespace"
<Application.Resources>
<core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
And then to wire up your view (ex: MainView.xaml) to your viewmodel:
<Window ...
DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
I don't understand why the other answers of this question wrap around the Designer.
The purpose of the View Model Locator is to allow your View to instantiate this (yes, View Model Locator = View First):
public void MyWindowViewModel(IService someService)
{
}
instead of just this:
public void MyWindowViewModel()
{
}
by declaring this:
DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
Where ViewModelLocator is class, which references a IoC and that's how it solves the MainWindowModel property it exposes.
It has nothing to do with providing Mock view models to your view. If you want that, just do
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
The View Model Locator is a wrapper around some (any) Inversion of Control container, such as Unity for example.
Refer to:
How to handle dependency injection in a WPF/MVVM application
http://blog.qmatteoq.com/the-mvvm-pattern-dependency-injection/

How to I connect a ViewModel to a View when the view model has parameters in the constructor?

I'm using Prism and Unity to rewrite a WPF application using the MVVM pattern. Most of the Views are connected to the VM via the DataContext property, like so:
<UserControl.DataContext>
<VM:RibbonViewModel/>
</UserControl.DataContext>
The problem is that this method will not work when there is a parameter in the ViewModel's constructor.
public RibbonViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
I get the error:
Type 'RibbonViewModel' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.
How do I connect the VM to the View when a parameter is there?
You might have a look at the sample applications of the WPF Application Framework (WAF). In these examples the IoC Container (in your case its Unity) is responsible to create the ViewModels. This way a ViewModel can have constructor parameters. The IoC Container is also responsible to bring the View with the ViewModel together. Maybe this is an option for your ViewModel design as well.
Consider using a ViewModelLocator. Rather than binding the datacontext to the ViewModel in your case above, you bind to a locator which knows how to resolve the ViewModel from the (unity) container and in the process inject any dependencies into the constructor. There's a blog posting summarizes an implementation by John Papa and Glenn Block (one of the people behind prism).
I believe the EventAggregator is registered with the container by default, so it should be auto-wired with the VM when you resolve the VM from the container.
I should mention the code from the above blog is using MEF. This blog I believe has a codeplex example using unity
I don't use unity or prism. But, why can't you just do this:
userControl.DataContext = ribbonViewModelInstance;
You can have a dependency property on the user control which is set. On setting of value of this dependency property, you can set the datacontext.

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