Loading Views and constructors

Topics: Prism v4 - WPF 4
Apr 2, 2012 at 11:04 PM

I have a question about the way Views are loaded. I have this sample code shown below of a view that loads correctly:

using System.Windows.Controls;
using Demo.Wpf.EmployeeModule.ViewModels;
using System.ComponentModel.Composition;
using Demo.Wpf.Infrastructure;
using Microsoft.Practices.Prism.Regions;


namespace Demo.Wpf.EmployeeModule.Views
{
    /// <summary>
    /// Interaction logic for EmployeeListView.xaml
    /// </summary>
    /// 
    [ViewExport(RegionName = RegionNames.LeftRegion)]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public partial class EmployeeListView : UserControl
    {
        [ImportingConstructor]
        public EmployeeListView(EmployeeListViewModel viewModel)
        {
            InitializeComponent();
            //this.DataContext = viewModel;
        }

        [Import]
        public EmployeeListViewModel Model
        {
            get
            {
                return DataContext as EmployeeListViewModel;
            }
            set
            {
                DataContext = value;
            }
        }

    }
}


NOtes:
1. I added an [ImportingConstructor] attribute to a parameterized constructor which is passing in the ViewModel.
2. I also have an [Import] attribute for the ViewModel setter so I can assign the DataContext.

However, in the Stocktrader demo the loading of the views is done differently. Look for example at the PositionSummaryView.xaml.cs file.

using System.ComponentModel.Composition;
using System.Windows.Controls;
using StockTraderRI.Infrastructure;

namespace StockTraderRI.Modules.Position.PositionSummary
{
    [ViewExport(RegionName = RegionNames.MainRegion)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class PositionSummaryView : UserControl
    {
        public PositionSummaryView()
        {
            InitializeComponent();
        }

        #region IPositionSummaryView Members

        [Import]
        public IPositionSummaryViewModel Model
        {
            get
            {
                return DataContext as IPositionSummaryViewModel;
            }
            set
            {
                DataContext = value;
            }
        }
        #endregion
    }
}

 
My questions are the following:
1. How is the View being instantiated without the [Importing Constructor] attribute for the class as shown in previous example?

2. What triggers the assignment of the DataContext property? How is value being passed to the ViewModel property ?  Whilst playing around with a modified version of StockTrader I created a new view. if I place a breakpoint next to the line DataContext = value, the breakpoint is never hit.

Any help to answer these questions would be enourmously appreciated.

Thank you

 


 

Developer
Apr 3, 2012 at 6:45 PM

Hi,

As far as I know, any type that is exported to MEF can be instantiated as long as it has a constructor without parameters. Also, based on my understanding, the ImportingConstructor attribute is only required when the class needs to be instantiated through a constructor that require one or more parameters. Therefore, in the first view, the ImportConstructor attribute is required as the constructor needs a parameter of type EmployeeListViewModel; on the other hand, as the second view's constructor doesn't need any parameter, it seems that MEF can instantiate it without using the aforementioned attribute.

Regarding the second question, as far as I know, the ImportingConstructor attribute and Importing attribute do not depend of each other:

  • Based on my understanding, when resolving a type through the container that has an ImportingConstructor attribute, MEF automatically inject instances of the corresponding types as parameters in the constructor. It does not modify any properties in the class or inject any dependencies in them.
  • If the type that is resolved through the container has an Import attribute in either a property or a field in the class, the container will try to inject instances of the corresponding types in them after the constructor has been invoked and finalized, regardless if the class has an ImportingConstructor or not.

Based on my understanding, in the first code snippet, an EmployeeListViewModel instance is being injected in the view twice: the first one in the constructor as a parameter (which is not used) and the second one as a value in the property. On the other hand, in the second code snippet, the IPositionSummaryViewModel is injected in the view only once: in the property.

You can find more information about this in the following page of MEF's codeplex site:

Also, we have checked that, with the Stock Trader RI as out of the box, the setter of the property of the aforementioned view is being called correctly when resolved through the container, after the constructor of the class has finalized.

As this is more related to the features provided by MEF, I believe you could also find support regarding this topic in the MEF forums:

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Apr 3, 2012 at 10:25 PM

Hi Damien,

Thank you very much for taking the time to answer my questions. I have a better understanding of the use of [ImportingConstructor] and [Import] attributes now. I'm still a bit puzzled about the setting of the ViewModel as show here:

       [Import]
        public IPositionSummaryViewModel ViewModel
        {
            get
            {
                return DataContext as IPositionSummaryViewModel;
            }
            set
            {
                DataContext = value;
            }
        }

You mentioned:
the setter of the property of the aforementioned view is being called correctly when resolved through the container, after the constructor of the class has finalized.

I need to know exactly how the container resolves this setting of the ViewModel property. I'll have a look at the MEF Community Site as you recommended. Again thank you for your help.