Showing posts with label Composite UI. Show all posts
Showing posts with label Composite UI. Show all posts

Friday, November 2, 2012

More about Catel and Prism in combination

Introduction

Since Catel 3.2 the support of Prism was enhanced. The fact is that several classes were introduced into Catel.Extensions.Prism to simplify the modules and bootstrapper implementation, and thanks to dependency injection support of the ServiceLocator everything can be done with Catel without the usage of third party containers.

But  now, with 3.4, a lot of improvements were introduced and the Prism extension is working like charm.

Lets take a look to a couple of scenarios.
 

Modularity with Catel explained

Probably you actually noticed the close resemblance of the UI with the Prism's Quick Start examples (with MEF or Unity). Actually this example is an adaptation of the original sources in order to show how use the Prism features in combination with Catel.

   

Here are some implementation details:

1) Catel comes with two versions of  generic classes, named BootstrapperBase, that helps to initialize with ease the shell and the module catalog. There are several methods that you are able to override, such as ConfigureContainer or ConfigureModuleCatalog, in order to setup the IoC container (a.k.a ServiceLocator) and the module catalog respectively, just like this:

    /// <summary>
    /// Initializes Prism to start this quickstart Prism application to use Catel.
    /// </summary>
    public class QuickStartBootstrapper : BootstrapperBase<Shell, CompositeModuleCatalog>
    {
        #region Fields

        /// <summary>
        /// The callback logger.
        /// </summary>
        private readonly CallbackLogger callbackLogger = new CallbackLogger();

        #endregion

        #region Methods

        /// <summary>
        /// Configures the <see cref="IServiceLocator"/>. May be overwritten in a derived class to add specific
        /// type mappings required by the application.
        /// </summary>
        protected override void ConfigureContainer()
        {
            base.ConfigureContainer();
            Container.RegisterTypeIfNotYetRegistered<IModuleTracker, ModuleTracker>();

            LogManager.AddListener(callbackLogger);

            Container.RegisterInstance<CallbackLogger>(callbackLogger);
        }

        /// <summary>
        /// Configures the <see cref="IModuleCatalog"/> used by Prism.
        /// </summary>
        protected override void ConfigureModuleCatalog()
        {
            ModuleCatalog.Add(Catel.Modules.ModuleCatalog.CreateFromXaml(new Uri("/ModularityWithCatel.Silverlight;component/ModulesCatalog.xaml", UriKind.Relative)));

            var moduleCatalog = new ModuleCatalog();
            // Module A is defined in the code.
            Type moduleAType = typeof(ModuleA.ModuleA);
            moduleCatalog.AddModule(new ModuleInfo(moduleAType.Name, moduleAType.AssemblyQualifiedName, "ModuleD"));

            // Module C is defined in the code.
            Type moduleCType = typeof(ModuleC.ModuleC);
            moduleCatalog.AddModule(new ModuleInfo { ModuleName = moduleCType.Name, ModuleType = moduleCType.AssemblyQualifiedName, InitializationMode = InitializationMode.OnDemand });

            ModuleCatalog.Add(moduleCatalog);
        }

        #endregion
    }

2) Catel also comes with the CompositeModuleCatalog class to deal with many catalog as one. The current implementation actually "allow" cross module catalog's module dependencies.

3) For a module implementation the common approach is  inherit from ModuleBase just like this:


    /// <summary>
    /// A module for the quickstart.
    /// </summary>
    public class ModuleA : ModuleBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ModuleA"/> class.
        /// </summary>
        /// </param name="moduleTracker">The module tracker.</param>        
        public ModuleA(IModuleTracker moduleTracker) : base("ModuleA", moduleTracker)
        {
        }
    }

4) The common implementation of the application class is about the instantiation of the Bootstrapper and making a call to the Run method.

var bootstrapper = new QuickStartBootstrapper();
bootstrapper.Run();

But, what will happend if you call RunWithSplashScreen instead? Try with the latest beta and discover the feature by your self or just take a look into orchesta.

Enhanced working with regions

Some time ago, I wrote about a feature where your were able to inject a view from a view model from it's view model:
 
 
	var employeeViewModel = new EmployeeViewModel();
	var uiVisualizerService = GetService<IUIVisualizerService>();
	uiVisualizerService.Activate(viewModel, "MainRegion");

1) But now you can deal with more than one shell and do this:

	uiVisualizerService.Activate(employeeViewModel, this, "MainRegion");

Where the second parameter is the parent view-model.

2) Actually you are able to inject views (referencing it's view models) in any window. Just like the previous example but in combination with the experimental extension method Show:

	var uiVisualizerService = GetService<IUIVisualizerService>();
	var windowViewModel = new WindowWithRegionViewModel();
	uiVisualizerService.Show(windowViewModel, () => { uiVisualizerService.Activate(new EmployeeViewModel(),  windowViewModel, "WindowMainRegion") });

Conclusions

1) The usage of third party Prism Extensions like MEF or Unity is no longer required. Catel Service Locator support dependency injection and is actually configured to work just as Prism expect, the fact is that the ServiceLocatorAdapter do this job.
 
2) Now, you are able to have a nice programming session with Prism & Catel.

Monday, May 14, 2012

Catel creates a perfect combination with PRISM

Introduction


I have been very "busy" watching the final of the baseball season. The past week, my team was eliminated on quarterfinals, so now I have  time to write.

Talking about competitions, I just remembered the history about how Catel.Extensions.Prism was born.

You may think that Catel and PRISM are competitors. The fact is that most people think that they are competitors. Actually I had the same idea when I discovered Catel, some time after I have been written LoB systems with PRISM. If you read the highlights, is not hard to notice the "isolated" features, mainly if you are looking for guidance or a stating point for the MVVM pattern implementation.

Catel has an out of the box view model base implementation, plus services, with full support for validation, property change notification and commanding. From my point of view Catel beats PRISM as MVVM pattern implementation guidance, with a cleaner approach on separation of views and view models and better testability. The fact is that PRISM has no a ViewModelBase implementation.

So, at some point, I considered removing all the PRISM references from my projects. But then I would loose many PRISM features, that allow you manage the modularity and view composition, that are hard to leave behind when you actually used it. I heard some people talking about the PRISM approach saying that it is a bit complex or strange. They provide example terms like bootstrapper, shell, module catalog, modules, region manager, etc. But the truth is that PRISM provides a good scaffold for modular application development.

That was the moment when we thought that they should be work together and that was the reason for we wrote Catel.Extensions.Prism and it is now available via NuGet.

User Interface Composition with Catel.Extensions.Prism


Starting with Catel 3.1 the Prism extension is available. PRISM includes a feature named "User Interface Composition". Basically it allows building a mosaic like application by loading multiple views that comes from different modules into an active region exposed by a control, also know as the shell.



The PRISM UI composition approach requires that you reference the view or the view type in order to associate it with one region. That is correct if you are coding a module class for instance, but all this is about view models.

In order to understand the code samples you need to read more about UIVisualizerService, and the way it can resolve a view from an instance of a view model. Now you are able to create a composite user interface without actually referencing any view from a view model class.

Making the region manager available

First of all, you must make available the region manager on the instance of ServiceLocator (IoC container of Catel). A PRISM based application uses MEF or Unity as primary IoC container. Therefore, you must synchronize this container with the Catel one, overriding the ConfigureContainer method of the application bootstrapper class, using the following code:

protected override void ConfigureContainer()
{
 base.ConfigureContainer();
 if (ServiceLocator.Instance.IsExternalContainerSupported(this.Container))
 {
  ServiceLocator.Instance.RegisterExternalContainer(this.Container);
 }
}

Activating a view into a specific region

To activate a view into a specific region from inside a view model, use the following code:
 var viewModel = new EmployeeViewModel();
 var uiVisualizerService = GetService<IUIVisualizerService>();
 uiVisualizerService.Activate(viewModel, "MainRegion");

Deactivating a view

To deactivate a view, use the following code:
uiVisualizerService.Deactivate(viewModel);

If you keep your view model alive (see: Keeping view models alive), you can reactivate a deactivated the view using Activate method without specify the region name. 

Deactivating a view automatically

If you close the view model using SaveAndCloseViewModel or CancelAndCloseViewModel or CloseViewModel methods, the view that belongs to this view model will be automatically deactivated from the region where it was activated.

Conclusions   

Nowadays, I enjoy write applications with Catel and PRISM, or with PRISM and Catel, the order doesn't matter. I will just give you one advice, try out this extension and like a host of a popular TV show that I know say, "draw your own conclusions by yourself" ;)

X-ray StoneAssemblies.MassAuth with NDepend

Introduction A long time ago, I wrote this post  Why should you start using NDepend?  which I consider as the best post I have ever...