Ian Oakes
Ian Oakes

Reputation: 10253

Getting a list of loaded modules from PRISM in WPF

I have a WPF application built on top of PRISM.

When the user tries to close the application I need to check the dirty status of any loaded views.

I was hoping to enumerate a list of the loaded modules and ask them in turn whether it's OK to exit and save any changes, but I'm having trouble finding a list of references to the loaded modules.

The closest I could find was IModuleCatalog which gives me a list of modules, but not the actual object references these modules

Any suggestions on how I can do this?

Thanks in advance

Ian

Upvotes: 3

Views: 5927

Answers (4)

Ondrej
Ondrej

Reputation: 606

According to answer from Shrike, I use a similar solution with sending events by IEventAggregator.

Firstly, I have simple event definition called ModulesDisposeRequested:

public class ModulesDisposeRequested : CompositePresentationEvent<object> { }

Then all modules, that need to be disposed are subscribing to this event:

// Module constructor
public ModuleA(IEventAggregator eventAggregator) {
   var evnt = eventAggregator.GetEvent<ModulesDisposeRequested>();
   if (evnt != null)
      evnt.Subscribe(OnModulesDisposeRequested);
}

private void OnModulesDisposeRequested(object payload) {
   // cleanup current module
}

When application is about to finish, bootstrapper publish this event:

// Overring in App.xaml.cs
protected override void OnExit(ExitEventArgs e) {
   var eventAggregator = _bootstrapper.Container.Resolve<IEventAggregator>();
   var evnt = eventAggregator.GetEvent<ModulesDisposeRequested>();
   if (evnt != null)
      evnt.Publish(null);

   base.OnExit(e);
}

Upvotes: 1

Shrike
Shrike

Reputation: 9500

I've implemented modules cleaning up on application shutdown in the following way.

I create "cleanup service" where modules can register their cleanup actions.

public interface IModuleCleanupService
{
    void RegisterCleanupAction(Action action);
}

public class ModuleCleanupService: IModuleCleanupService
{
    private readonly List<Action> m_cleanupActions = new List<Action>();

    public void RegisterCleanupAction(Action action)
    {
        m_cleanupActions.Add(action);
    }

    public void Cleanup()
    {
        List<Exception> exceptions = null;
        foreach (Action action in m_cleanupActions)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                if (exceptions==null)
                    exceptions = new List<Exception>();
                exceptions.Add(ex);
            }
        }
        if (exceptions != null)
            throw new AggregateException(exceptions);
    }
}

Then any module can import IModuleCleanupService-instance. This can be done in different ways (with MEF/Unity via contructor injection or through asking the ServiceLocalor.Current)

The service's instance is created in Bootstapper's ConfigureContainer (here I'm using MefBootstapper deviced type, but this isn't important):

protected override void ConfigureContainer()
{
    base.ConfigureContainer();

    m_moduleCleanupService = new ModuleCleanupService();
    Container.ComposeExportedValue<IModuleCleanupService>(m_moduleCleanupService);
}

Then I add GetDisposable method to my bootstapper which returns IDisposable-object. That IDisposable-object simple calls Cleanup on ModuleCleanupService:

public IDisposable GetDisposable()
{
    return new DisposableDelegate(() => m_moduleInitializationService.Cleanup());
}

class DisposableDelegate: IDisposable
{
    private readonly Action m_action;

    public DisposableDelegate(Action action)
    {
        m_action = action;
    }

    public void Dispose()
    {
        m_action();
    }
}

Upvotes: 2

Konamiman
Konamiman

Reputation: 50323

If what you want to do is to obtain the existing instance of all the loaded modules, you can do the following:

  1. Get the existing instance of IServiceLocator from the Unity container.
  2. For each instance of ModuleInfo in the module catalog where the state is Initialized, get the module instance by using serviceLocator.GetInstance(moduleInfo.ModuleType)

Upvotes: 0

Anderson Imes
Anderson Imes

Reputation: 25650

Have you considered a composite command for this, rather than your current approach? It seems like your views ought to be participating in the closing of the application, rather than some central bit of module logic.

This sample (called the Commanding Sample, which I think is great to say... it's very commanding) illustrates a "Save All" which is very similar to your "Close All" (basically what you are doing). The thing that is great here is that this is functionality baked in that you don't have to build yourself: http://msdn.microsoft.com/en-us/library/dd458890.aspx

Upvotes: 4

Related Questions