MVVM - Does the View really need have to have a default constructor? - wpf

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.

Related

WPF - Using behaviors for instantiating view model and services

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

Prism-WPF equivalent to Silverlight's: CompositionInitializer class and SatisfyImports()

i'm using Prism-MEF-WPF and Sometimes i need view model gets constructed from the XAML
of the view, so the container is not involved and can’t do the dependency injection
automatically (as there is no Export attribute used with VM).so there should be some
class in Prism-WPF like CompositionInitializer to enable me to ask the container to
do the injection.In case there is equivalent class how to use it, and in case there is
no equivalent how to construct view model from xaml of the view knowing that i use MEF.
Thanks in advance.
The problem is that you can't create an object in XAML if it doesn't have a parameterless constructor.
Using the ServiceLocator, you can achieve this. It will work as an IoC (and is set up by Prism/MEF, you just have to drop the .dll):
The xaml:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
The code-behind:
class ViewModel : NotificationObject
{
public ViewModel()
{
var firstDependency = ServiceLocator.Current.GetInstance<FirstDependencyType>();
//... more dependencies here instead of as constructor parameters
}
//class code omitted for brievity
}
Here is the right answer which i got from Agustin Adami "http://blogs.southworks.net/aadami":
Based on my understanding the view model can be instantiated in XAML as the view’s DataContext only if a view model does not have any constructor arguments. And as far as I know creating objects defined in XAML by partnering with an Inverse of Control Container is currently not supported.
Regarding the CompositionInitializer class, as far as I know there is no equivalent class for WPF, on the other hand regarding this topic, I believe you could find the following blog post interesting:
•http://reedcopsey.com/2010/03/26/mef-compositioninitializer-for-wpf/
Also, I believe an alternative for this could be registering the CompositionContainer class like mentioned in this thread:
http://compositewpf.codeplex.com/discussions/311933
As this could let you retrieve this class for example in your view model's constructor, in order to call the SatisfyImportsOnce method to satisfy the Imports defined in the passed class:
this.compositionContainer =ServiceLocator.Current.GetInstance();
this.compositionContainer.SatisfyImportsOnce(this);
Bootstrapper class is what you are looking for. It uses UnityContainer for injecting dependencies. This link here might be of your interest too..
EDIT
If i am getting right, you want to create a ViewModel from your xaml which can be achieved like this(Here local is namespace of your ViewModel class) -
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>

passing data to a mvvm usercontrol

I'm writting a form in WPF/c# with the MVVM pattern and trying to share data with a user control. (Well, the User Controls View Model)
I either need to:
Create a View model in the parents and bind it to the User Control
Bind certain classes with the View Model in the Xaml
Be told that User Controls arn't the way to go with MVVM and be pushed in the correct direction. (I've seen data templates but they didn't seem ideal)
The usercontrol is only being used to make large forms more manageable so I'm not sure if this is the way to go with MVVM, it's just how I would of done it in the past.
I would like to pass a class the VM contruct in the Xaml.
<TabItem Header="Applicants">
<Views:ApplicantTabView>
<UserControl.DataContext>
<ViewModels:ApplicantTabViewModel Client="{Binding Client} />
</UserControl.DataContext>
</Views:ApplicantTabView>
</TabItem>
public ClientComp Client
{
get { return (ClientComp)GetValue(ClientProperty); }
set { SetValue(ClientProperty, value); }
}
public static readonly DependencyProperty ClientProperty = DependencyProperty.Register("Client", typeof(ClientComp),
typeof(ApplicantTabViewModel),
new FrameworkPropertyMetadata
(null));
But I can't seem to get a dependancy property to accept non static content.
This has been an issue for me for a while but assumed I'd find out but have failed so here I am here.
Thanks in advance,
Oli
Oli - it is OK (actually - recommended) to split portions of the View into UserControl, if UI became too big - and independently you can split the view models to sub view models, if VM became too big.
It appears though that you are doing double-instantiations of your sub VM. There is also no need to create Dependency Property in your VM (actually, I think it is wrong).
In your outer VM, just have the ClientComp a regular property. If you don't intend to change it - the setter doesn't even have to fire a property changed event, although it is recommended.
public class OuterVm
{
public ClientComp Client { get; private set; }
// instantiate ClientComp in constructor:
public OuterVm( ) {
Client = new ClientComp( );
}
}
Then, in the XAML, put the ApplicantTabView, and bind its data context:
...
<TabItem Header="Applicants">
<Views:ApplicantTabView DataContext="{Binding Client}" />
</TabItem>
I answered a similar question as yours recently: passing a gridview selected item value to a different ViewModel of different Usercontrol
Essentially setting up a dependency property which allows data from your parent view to persist to your child user control. Abstracting your view into specific user controls and hooking them using dependency properties along with the MVVM pattern is actually quite powerful and recommended for Silverlight/WPF development, especially when unit testing comes into play. Let me know if you'd like any more clarification, hope this helps.

How is the DataContext typically set?

I've created a new WPF project, and threw in a DataGrid. Now I'm trying to figure out the easiest way to bind a collection of data to it.
The example I downloaded seems to do it in the window c'tor:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
But then the bindings don't seem to appear in the Visual Studio's Properties window. I'm pretty sure there's a way to set the data context in XAML too... it would make me even happier if I could do it directly through the properties window, but all the Binding options are empty. What's the typical approach?
Edit: At 14 minutes, he starts to talk about other methods of setting the data context, such as static resources, and some "injection" method. I want to learn more about those!
What I typically do is use MVVM. You can implement a simplified version by setting the data context in your code behind and having a model type class that holds your data.
Example: In your code behind
DataContext = Model; // where Model is an instance of your model
then in your view
<DataGrid .... ItemsSource="{Binding SomeProperty}">....
Where SomeProperty is an enumerable property on your view model
You can also set a data context in XAML by using the DataContext property
<uc:SomeUserControl DataContext="{Binding AnotherProperty}"....
This will run your user control within the DataContext of the AnotherProperty on your model.
Note that this is grosely simplified but it'll get you on your way.
Have a look at the MVVM design pattern. This pattern is very suitable for wpf applications.
There is described where to store your data and how to bind your ui to the data.

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