Quantcast
Channel: patterns & practices: Prism
Viewing all articles
Browse latest Browse all 1878

New Post: Creating a multple window app like Outlook

$
0
0
I see how that would work after looking at the IG Outlook’s XamRibbonRegionBehavior and RibbonTabAttribute code. Once the custom RegionBehavior knows the region and view names, I could call Region.RegionManager.RequestNavigate() from within the custom RegionBahavior class.

However, some modules require much more initializations than just calling a RequestNavigate(). I needed to resolve business classes, create view models with the resolved business classes, create corresponding views, and finally add them to the region to use view injection. In other words, I needed the DI container and needed to call a part of IModule.Initialize() of every module that is used inside the shell.

So, rather than creating a separate DialogService as is done in the IG Outlook sample, I assigned the responsibility to the Bootstrapper and created an interface for the module classes so that I can separate the IModule.Initialize() in two sections – one that registers types and the other that does everything else including initializing the regions with a given region manager.

This scheme seems to be working very well. Now, I don’t need the custom behavior. The part of the Bootstrapper code is as follows:
protected override void InitializeModules()
{
    var regionManager = this.Container.Resolve<IRegionManager>();
    this.Container.RegisterType<object, MainView>("MainView");
    regionManager.RequestNavigate(RegionNames.MainRegion, "MainView");

    var eventAggregator = this.Container.Resolve<IEventAggregator>();
    const bool KeepMeAlive = true;
    eventAggregator.GetEvent<CreateNewWindowEvent>().Subscribe(this.CreateNewShell, ThreadOption.UIThread, KeepMeAlive);

    base.InitializeModules();
}

private void CreateNewShell(string obj)
{
    var newShell = this.Container.Resolve<ShellView>();
    var regionManager = this.Container.Resolve<IRegionManager>();
    var scopedRegionManager = regionManager.CreateRegionManager();
    RegionManager.SetRegionManager(newShell, scopedRegionManager);
    scopedRegionManager.RequestNavigate(RegionNames.MainRegion, "MainView");

    this.InitializeModulesForTheNewShell(scopedRegionManager);

    newShell.Show();
}

private void InitializeModulesForTheNewShell(IRegionManager scopedRegionManager)
{
    foreach (var moduleInfo in this.ModuleCatalog.Modules)
    {
        var moduleType = Type.GetType(moduleInfo.ModuleType);
        var module = this.Container.Resolve(moduleType) as IModuleWithMultipleShells;
        if (module != null)
        {
            module.InitializeRegion(scopedRegionManager);
        }
    }
}
Since the above is done in the Bootstrapper, the ModuleCatalog is easily available. The InitializeModulesForTheNewShell() calls InitializeRegion() that is to be implemented in the IModule classes if need be. Below shows an example of such a module:
public void Initialize()
{
    this.container.RegisterType<object, ViewA>("ViewA");
    this.InitializeRegion(this.regionManager);
}

public void InitializeRegion(IRegionManager rm)
{
    rm.RequestNavigate(RegionNames.ViewARegion, "ViewA");
}
The IModuleWithMultipleShell interface looks like this:
public interface IModuleWithMultipleShells
{
    void InitializeRegion(IRegionManager scopedRegionManager);
}
With this implementation, all of my issues with the scoped region manager except for #3 are gone. I still miss view discovery because it’s simpler, but I can live with that.

With that said, our team will go with the multiple bootstrapper approach because it needs a lot less code and less confusing. When we see an unexpected problem related to this decision in future, we should be able to switch to the scoped region manager without much pain.

Again, thank you for your extremely helpful pieces of advice. I really appreciate it.

Viewing all articles
Browse latest Browse all 1878

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>