3

Technologies

  • C# 4.0
  • Prism 4 with Unity for DI
  • WPF
  • MVVM

Preface

There are two projects in my solution, MyApp.Shell and MyApp.ModuleFoo

MyApp.Shell's Unity Bootstrapper

protected override IModuleCatalog CreateModuleCatalog()
{
    // Module assemblies are read from a directory.
    DirectoryModuleCatalog moduleCatalog = new DirectoryModuleCatalog();
    moduleCatalog.ModulePath = @".\Modules";
    return moduleCatalog;
}

The project MyApp.ModuleFoo contains a View and a View Model.

The ViewModel

// Somehow, Unity sees this class and registers the type.
public class FooViewModel : ViewModelBaseClass
{
    public string FooText
    {
        get { return "Foo!"; }
    }
}

The View

<Label Content={Binding FooText} />

The View's Code-behind

// Unity automatically sees this as Constructor Injection, 
// which is exactly what I desire.
public FooView(FooViewModel viewModel)
{
    DataContext = viewModel;
    ...
}

MyApp.FooModule's Initialization

Perhaps registering FooView with the region manager is inadvertently registering FooViewModel with Unity?

public void Initialize()
{
    var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
    regionManager.RegisterViewWithRegion("FooRegion", typeof(FooView));
}

The view correctly displays "Foo!".

Problems

  • How do I tell Unity to register only a single instance of FooViewModel?
  • Additionally, (and I'm thinking ahead here), how would I tell unity not to register FooViewModel?

Thanks for the help.

Edit:

Added MyApp.FooModule's Initialization code

Edit (Solution):

It turns out RegisterViewWithRegion has two overloads. From Prism's documentation, when the overload I'm using is used, a new instance of the view is created. I'm assuming this also creates a new instance of FooViewModel.

The other overload uses a delegate to resolve FooView. The documentation says this overload is used in the "ViewModel-first" approach. I'm going to make this question as answered, but if anyone has any additional insight, I'd love to hear.

Nick Carlson
  • 243
  • 1
  • 5
  • 13

1 Answers1

4

// Somehow, Unity sees this class and registers the type. public class FooViewModel : ViewModelBaseClass ...

I am surprised that you say this as Unity does not register types inside the container by default. You have to tell it to do so either programmatically or in the config file.

When you have concrete classes (not interfaces) they will automatically get created by Unity whether they are registered or not. If not the default behavior is to create a new instance each time. No lifetime management is applied also.

As far as your questions:

To register only one type within your initialisation of your module just have.

Container.RegisterType<FooViewModel>(new ContainerControlledLifetimeManager());

The lifetime manager will instruct unity to only create one instance of the view model.

mathieu
  • 30,974
  • 4
  • 64
  • 90
aqwert
  • 10,559
  • 2
  • 41
  • 61
  • Here was my assumption. Within the CreateModuleCatalog method, I tell Prism which directory it can find my assemblies in. Prism then uses reflection to build a dependency graph. It sees that FooView needs a FooViewModel and subsequently registers the type.. Am I wrong here? If I am, where exactly is FooViewModel being registered? The only place I can think of is the code which registers FooView with the region manager. (I'll update my post to reflect FooModule.Initialize().) – Nick Carlson May 12 '11 at 04:08
  • I am not too sure what Prism is looking for but I suspect it is trying to look for Modules. Unity itself wont register types unless instructed to do so. I cann't say the reason it is registering the view model is because of Prism. Although I would hope it wouldn't besides you do not need to register a type in Unity for it to create it if it is part of a constructor of the View. It will simply try to create a new instance of the view model each time. – aqwert May 12 '11 at 04:24
  • 1
    FooViewModel is not registered. The DI container detects the dependency of the view and tries to resolve it. As far as it is a well-defined type it uses the most common constructor of this type to resolve an instance. To verify this you can make a IFooViewModel interface and make FooView dependend on IFooViewModel. Unity will not be able to resolve the interface request because it does not know which type implements this interface. – PVitt May 12 '11 at 06:10
  • 2
    Yes, when you have concrete classes (not interfaces) they will automatically get created by Unity whether they are registered or not. If not the default behavior is to create a new instance each time. No lifetime management is applied also. – aqwert May 12 '11 at 07:38