
Composite WPF comes with the notion of modules, but without any standard classes for controllers and/or viewmodels. This might sound weird to developers who have worked with the Composite Application Block before. In this post we will talk about how you can create them yourself and why base classes for these constructions aren't actually required.
Introduction to the use case controller
Often you implement use cases inside a controller that shows and hides all the required user interface parts and lets you navigate through the steps of the use case. It's the central part of the use case. In Composite WPF Microsoft took extra care to make it possible to create controllers with zero interference from user interface components or any framework components for that matter.
In fact, the use case controller in Composite WPF is nothing more than a class on which you can invoke a method to start the use case. The rest is a matter of letting the controller handle all the required logic. There is no need to derive from any base class whatsoever.
What if you need stuff from composite WPF
Often just building the controller isn't enough and you need services offered by Composite WPF or services that you have registered on the IoC container in the application. At this point it's good to know that you can make use of unity to let it inject the required components in the controller. A sample of a class utilizes this principle is shown below.
1 public class CreateProjectController
2 {
3 private IUnityContainer _container;
4 private IEventAggregator _eventAggregator;
5
6 /// <summary>
7 /// Initializes a new instance of the CreateProjectController class.
8 /// </summary>
9 /// <param name="container"></param>
10 public CreateProjectController(IUnityContainer container)
11 {
12 _container = container.CreateChildContainer();
13 _eventAggregator = _container.Resolve<IEventAggregator>();
14
15 RegisterTypes();
16 }
17 }
Initializing the controller can be done with one line of code:
1 /// <summary>
2 /// Starts the create project use case
3 /// </summary>
4 /// <param name="arg"></param>
5 void CreateProject(object arg)
6 {
7 CreateProjectController controller = _container.Resolve<CreateProjectController>();
8 controller.CreateProject();
9 }
The interesting part here is the fact that I created a child container for the controller instead of using the controller provided in the constructor. I will get back to that in a second. This small piece of code can be extended further to retrieve for example the event aggregator service or the module loader.
The use of child containers
The reason why I created a childcontainer is because this allows me to implement a wide variety of scenarios that are often required inside applications. One of the things that you can do is have a registered type that has a single instance per container. This may sound not so useful, but what if you needed a single instance for each time you started a use case. You can't do that without the use of a child container.
How container hierarchies work
Unity supports container hierarchies by creating child containers. This allows you to isolate type registrations from other containers. When resolving a type from the container unity will first try to resolve the type in the current container. If the type is not found in the current container, unity will move up one level in the hierarchy and tries to resolve the type there. This continues up to the root container.
So if you register a type in the root container, it is available in all child containers, however if you register a type in a child container it is not available in a container on the same level or in a container higher in the hierarchy.
General tips
There are some general tips and tricks that can help you get more out of this construction. Here's a list:
- Register global services in the root container
By registering services in the root container you make them available to all modules in your Composite WPF application. Just make sure you reference the contract of the service in the modules where you need the service and you have a great service locator. - Make use of the ContainerLifecycleManager class
When you need a singleton instance of a class you can register an instance of the type, however this requires you to create the instance of the class at the moment you register it as a singleton. You can conserve memory by registering the type with a new instance of the ContainerControlledLifetimeManager. This makes the type a singleton in the current container. If you do this at the right level you can control where the singleton instance is available. - Using the container is a good thing, but don't overdo it
Creating instances of classes through the container can be useful, especially if you need to inject several dependencies. However don't use the container as a generic factory for all objects. Instead take a good look if you need to create the instance through the use of the unity container and don't use it if you don't have to.
Conclusion
The unity container is essential to Composite WPF and a very powerfull tool when used correctly. I hope this article helped getting a better picture of it's use in combination with use case controllers.