Prism, connecting Views and ViewModels with Unity,

2019-03-15 13:29发布

问题:

Creating the View and View Model Using Unity

Using Unity as your dependency injection container is similar to using MEF, and both property-based and constructor-based injection are supported. The principal difference is that the types are typically not implicitly discovered at run time; instead, they have to be registered with the container.

Typically, you define an interface on the view model so the view model's specific concrete type can be decoupled from the view. For example, the view can define its dependency on the view model via a constructor argument, as shown here. C#

public QuestionnaireView() 
{
    InitializeComponent(); 
}

public QuestionnaireView(QuestionnaireViewModel viewModel) : this() 
{
    this.DataContext = viewModel;
}

The default parameter-less constructor is necessary to allow the view to work in design-time tools, such as Visual Studio and Expression Blend.

Alternatively, you can define a write-only view model property on the view, as shown here. Unity will instantiate the required view model and call the property setter after the view is instantiated. C#

public QuestionnaireView() 
{
    InitializeComponent(); 
}

[Dependency] 
public QuestionnaireViewModel ViewModel 
{
    set { this.DataContext = value; } 
}

The view model type is registered with the Unity container, as shown here. C#

IUnityContainer container;
container.RegisterType<QuestionnaireViewModel>();

The view can then be instantiated through the container, as shown here. C#

IUnityContainer container;
var view = container.Resolve<QuestionnaireView>();
  1. If I leave out the last part of the code regarding registering the ViewModel and instantiating the View, and just use either of the two methods of hooking the ViewModel to the View here (using a constructor or using a property) it seems the ViewModel and View it seems everything is working fine. So what is the need for the code registering the ViewModel and instantiating the View?

  2. The first example, hooking the View and ViewModel using a constructor, has no mention of Unity of all, so is Unity actually being used here?

  3. Are there any advantages of using property-based injection over construtor based injection or are they exactly the same thing?

  4. The first part of the text says "*Typically, you define an interface on the view model so the view model's specific concrete type can be decoupled from the view", and then gives an example. Yet this example makes no mention of interfaces at all. What is going on here, am I missing something?

回答1:

To answer questions 1 & 4

In your example, the viewmodel is of type QuestionnaireViewModel, which is a concrete class. Since it's a concrete class, when you resolve the view using container.Resolve<QuestionnaireView>(), unity will instantiate the viewmodel for you by calling container.Resolve<QuestionnaireViewModel>() behind the scenes.

In this case, registering your viewmodel is redundant. However, when using dependency injection you usually want to work with interfaces rather than classes, so your constructor would look like this:

public QuestionnaireView(IQuestionnaireViewModel viewModel)
{
    this.DataContext = viewModel;
}

Now that your constructor receives an interface rather than a class as a parameter, Unity doesn't know which implementation of the interface you'd like to use. To tell Unity that, you need to register your viewmodel to the container:

container.RegisterType<IQuestionnaireViewModel, QuestionnaireViewModel>();

so now when you resolve your view, Unity will look up which class it should use as an implementation of IQuestionnaireViewModel, see that it's QuestionnaireViewModel and use it.

To answer question 2

Unity is being used, since in order for the constructor to get its parameters, you need to resolve the view using the container. Unity is not used if you instantiate the view yourself using new QuestionnaireView(), i.e. no constructor or property injection will occur.

To answer question 3

I think it's mostly a matter of what's more comfortable and where you need to use the injected members. A lot of times you just want to set a local variable in the constructor and not create a property just for performing the injection.

One good thing about property-injection though is the fact that you can use the container.BuildUp() method for instances that were created by using new rather than container.Resolve<>(). This way, you can inject members into properties even after creation - which is something you can't do with constructor injection.