1
votes

I am creating a application with Prism and Unity. I use the DirectoryModuleCatalog to load several modules from disk which are displayed in a main menu and when you click on the name of this particular module the UI of this module gets loaded. Each module is designed according to the MVVM model, so with a separate view and view model.

Bootstrapper:

class Bootstrapper : UnityBootstrapper
{
   protected override DependencyObject CreateShell()
   {
        Shell shell = Container.Resolve<Shell>();
        shell.Show();
        return shell;
   }

   protected override void InitializeShell()
   {
        base.InitializeShell();
        App.Current.MainWindow = (Window)this.Shell;
        App.Current.MainWindow.Show();
   }

   protected override void ConfigureContainer()
   {
       base.ConfigureContainer();
       Container.RegisterType<IApplicationMenuRegistry, MenuRegistry>();
       Container.RegisterType<IApplicationCommands, ApplicationCommands>();
       Container.RegisterType<ShellViewModel, ShellViewModel>(new Microsoft.Practices.Unity.ContainerControlledLifetimeManager());

       //****** When I uncomment following line, the HelloWorldModule2 doesn't get initialized ***********
       // Container.RegisterType<HelloWorldModule2ViewModel, HelloWorldModule2ViewModel>(new Microsoft.Practices.Unity.ContainerControlledLifetimeManager());
    }


    protected override IModuleCatalog  CreateModuleCatalog()
    {
        return new DirectoryModuleCatalog() { ModulePath = @"C:\Data\NPC Service Tool\Source\develop\POC\GUIWithPrism\Modules" };

    }
}

Module:

namespace HelloWorldModule2
{
    [Module(ModuleName="HelloWorldModule2")]
    public class HelloWorldModule2 : IModule
    {
        private IApplicationMenuRegistry menuRegistry;
        private HelloWorldModule2ViewModel viewModel;
        private IRegionManager regionManager;
        public HelloWorldModule2(IApplicationMenuRegistry menuRegistry, HelloWorldModule2ViewModel vm, IRegionManager regionManager)
        {
            this.menuRegistry = menuRegistry;
            this.regionManager = regionManager;
            this.viewModel = vm;
        }

        public void Initialize()
        {
            ObservableCollection<ViewObject> views = new ObservableCollection<ViewObject>();
            views.Add(new ViewObject() { Region = RegionName.Right, ViewType = typeof(HelloWorld2View) });
            views.Add(new ViewObject() { Region = RegionName.Left, ViewType = typeof(View2) }); 

            //****** Here the module gets registered in the main menu ******//
            menuRegistry.RegisterModuleMenuItem("HelloWorld2", "Hello World module 2",views,1);
            this.viewModel.Title = "Hello world module 2";
        }
    }
}

View Model:

namespace HelloWorldModule2.ViewModels
{
    public class HelloWorldModule2ViewModel : NotificationObject
    {
        private string title;

        public string Title
        {
            get { return title; }
            set
            {
                title = value;
                RaisePropertyChanged(() => this.Title);
            }
        }
    }
}

I ran into the following problem: When i register the view model in the Unity container as seen in the Bootstrapper code, my module doesn't get initialized (I set a breakpoint in the Initialize method of the module but it never hits). If I remove the registration and remove the vm parameter in the constructor of the module, the module DOES initialize.

Also when i manual configure the module catalog with this module with:

protected override void ConfigureModuleCatalog()
{
   base.ConfigureModuleCatalog();
   ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
   moduleCatalog.AddModule(typeof(HelloWorldModule2.HelloWorldModule2));
}

instead of the DirectoryModuleCatalog, it initializes correctly even WITH the registration of the view model.

2

2 Answers

1
votes

I fear that you have misunderstood the purpose of the module class. The module class is used to register the classes that are provided in the modules assembly. It is solely for infrastructural purposes. So don't try to put any business logic inside a module class.

The reason why your breakpoint isn't hit is that the DI container cannot resolve the injected type HelloWorldModule2ViewModel. You try to use the DI container before it is initialized, so the initialization process gets aborted by exception.

Please have a look at the Prism manual and carefully read chapter 2. Also have a look at the reference implementation.

1
votes

I know this question is old, but I came across trying to research a similar problem. Since I couldn't find a good answer, I'm hoping leaving one here helps.

I am using Prism and DirectoryModuleCatalog to load IModule instances to plug in components to my application. This has worked well for years, but I discovered one of my modules wasn't loading when I tried to add some functionality to it. No exceptions showing in Output or anything - module just wouldn't initialize. The dll itself was loaded and I could use classes from it, even dynamically accessed classes.

After considerable research, I stumbled upon the fact that this module had a class referenced in the config file for the shell application (to load a custom sql provider). When I removed that reference, the module initialized just fine. This is similar to you commenting out the code above that registers a type from your module library.

My conclusion (not entirely verified) is that if the module library is already loaded, then the DirectoryModuleCatalog or Module Loader encounters an exception when loading the library for reflection only, and can't/won't run the initialization on the Module. This seems like a bug in the module loader, especially since no error/log appears to be generated and it just silently fails. Haven't delved deep enough into debugging Prism module loaded to confirm.

I think my solution is to separate out the custom sql provider into a separate library, even though I don't think I should have to do that.