LoadModule problem when OnDemand

Topics: Prism v4 - WPF 4
Nov 4, 2010 at 7:17 PM

I am using WPF, Unity, Prism 4 drop 10 (recompiled with fix for removing a view when using ItemControl). I am loading my modules through a ModuleCatalog and all of them are setup to be loaded on demand.

My button command calls the following code:

void NavigateExecute(String uri)
        {

            if (!_loadedModules.Contains(uri))
            {
                _loadedModules.Add(uri);
                
                _moduleManager.LoadModule(uri);
            }

            _regionManager.RequestNavigate(RegionNames.MainContentRegion, new Uri(uri, UriKind.Relative), Callback);
        }

Everything is fine if I load modules and navigate between them. I have a close button, which publishes a close event and the module to close. All the modules subscribe to this event and if they are the module being targeted for closure, they run the following code:

private void OnCloseClick(string viewName)
        {
            if (viewName == "TestModule2SummaryView")
            {
                if (_navigationJournal.CanGoBack)
                {
                    _keepAliveState = false;
                    _navigationJournal.GoBack();
                }
            }
        }

where the variable _keepAliveState is used to implement IRegionMemberLifetime.KeepAlive. The module correctly appears to unload. However the problem occurs if I try to load the unloaded module a second time. In the Prism.Modularity.ModuleManager, the method LoadModuleTypes cycles through the IEnumerable<ModuleInfo> and checks the state. The first time through, the State = ModuleState.NotStarted, which is obviously correct. However, after it unloads, the second time it tries to load the module, the state = Initialized, and the loading fails. If I breakpoint it and manually set the state to ReadyForInitialization, everything works fine. 

Am I doing something wrong or is there a bug with the ModuleManager in my scenario?

Thanks

Nov 4, 2010 at 7:30 PM
Edited Nov 4, 2010 at 7:30 PM

For what it's worth, if I change LoadModuleTypes in the ModuleManager.cs from this

 

 private void LoadModuleTypes(IEnumerable<ModuleInfo> moduleInfos)
        {
            if (moduleInfos == null)
            {
                return;
            }

            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                if (moduleInfo.State == ModuleState.NotStarted)
                {
                    if (this.ModuleNeedsRetrieval(moduleInfo))
                    {
                        this.BeginRetrievingModule(moduleInfo);
                    }
                    else
                    {
                        moduleInfo.State = ModuleState.ReadyForInitialization;
                    }
                }
            }

            this.LoadModulesThatAreReadyForLoad();
        }

 

To this

 

 private void LoadModuleTypes(IEnumerable<ModuleInfo> moduleInfos)
        {
            if (moduleInfos == null)
            {
                return;
            }

            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                if (moduleInfo.State == ModuleState.NotStarted || moduleInfo.State == ModuleState.Initialized)
                {
                    if (this.ModuleNeedsRetrieval(moduleInfo))
                    {
                        this.BeginRetrievingModule(moduleInfo);
                    }
                    else
                    {
                        moduleInfo.State = ModuleState.ReadyForInitialization;
                    }
                }
            }

            this.LoadModulesThatAreReadyForLoad();
        }

Everything appears to work.

 

Nov 4, 2010 at 8:51 PM

Hi,

Thanks for reporting that. Please take into account that modules can no be unloaded. You could either remove or deactivate a view from a region, but it is not possible to unload a module.

Modules can be loaded on demand, but once a modules are loaded, they will be unloaded when closing the application.

Are you really trying to unload a module?

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Nov 4, 2010 at 9:15 PM

Sorry, I used the wrong terminology. You are correct, I am not actually trying to unload the module. Just removing the view from the region. Thanks.

Nov 4, 2010 at 10:30 PM

Hi,

When you set KeepAlive to False, it will remove a view from a region if it is deactivated. As you mentioned it is working. So, based on my understanding when you call the RequestNavigate method passing a uri of a view and this was previously removed, it is not added to the region again.

First of all, I assume that the view is not removed from the container at any time, and that the view name is equal to the module name in all your modules, since the uri variable is passed to load a module as well as to navigate a view in the NavigateExecute method.

I am not aware how the update to the LoadModuleTypes method can help on this scenario, since it is executed only the first time that module is being loaded:

if (!_loadedModules.Contains(uri))
{
_loadedModules.Add(uri);
_moduleManager.LoadModule(uri);
}

I can not figure out how the update to the LoadModuleTypes method can help on this scenario, since it is executed only the first time that module is being loaded.

Please, let me know if I missing something. If you continue experiencing this problem in your scenario, could you please share a repro sample (application).

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Nov 5, 2010 at 2:46 PM

 

Yes, the view deactivates and is removed from the region, but when I try to navigate to the view again, I would expect it to have a state of NotStarted, since it was deactivated. However, it has a state of Initialized, which it isn’t.

When I changed that line, it checks if the ModuleNeedsRetrieval, which returns false, so the state is set to ReadyForInitialization. Without that change, when it runs LoadModulesThatAreReadyForLoad, it doesn’t get picked up in the availableModules enumerable and therefore , the InitializeModule is never called and rather than seeing a view, I see the words System.Object.

I do have a sample application, but it is using the Infragistics XAMRibbon for some other things I am testing. If you have Infragistics, I can send you the code as-is. If not, let me know and I will make a version just using buttons.

P.S. I don't think that my fix is solving the root of the problem, which is why the state is Initialized after it was deactivated. My solution is a band-aid over what I think is the real problem which is an incorrect state.

Thanks.

Nov 5, 2010 at 3:13 PM

I put a button version of my test application which demonstrates the problem on dropbox.

http://dl.dropbox.com/u/4053682/AOPC.Navigation.zip

 

Nov 5, 2010 at 9:41 PM
Edited Nov 5, 2010 at 10:23 PM

Hi,

Thanks for sharing your repro sample. I was able to reproduce this situation and found that it is caused because in this scenario there is a mix between View Discovery and Navigation. So, you could modify the Initialize methods of your modules using the following code:

public void Initialize()
{
this.container.RegisterType<Object, TestModule1SummaryView>("TestModule1SummaryView");
//this.regionManager.RegisterViewWithRegion("DisplayRegion", () => container.Resolve<TestModule1SummaryView>());
}

As your views do not implement any view interface (e.g. ITestModule1SummaryView) you have to indicate the TTo as Object in the RegisterType method. If you need more information on this topic you could take a look at the following work-item: Activate View only from RegionManager.RequestNavigate. Please, see Bob Brumfiled's comments about this.

Please, take into account that the code is reloading Modules in some cases in the following piece of code. Once a module is loaded, it is not recommended to try to unload or reload it.

if (!_loadedModules.Contains(uri))
{
_loadedModules.Add(uri);
_moduleManager.LoadModule(uri);
}

Additionally, I simplified your repro sample to use only one module. You could download this from here as a reference.

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 


Nov 8, 2010 at 2:38 PM

Thanks for your time on this Fernando. I will try out your recommended changes.

Nov 8, 2010 at 2:55 PM

That fixed all my problems. Not only that problem, but other problems I was having that I didn't ask yet. You have saved me from another day of frustration. Thanks again.