English 中文(简体)
Getting a list of loaded modules from PRISM in WPF
原标题:
  • 时间:2009-12-03 06:09:19
  •  标签:
  • wpf
  • prism

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

问题回答

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

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();
    }
}

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);
}

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)




相关问题
WPF convert 2d mouse click into 3d space

I have several geometry meshes in my Viewport3D, these have bounds of (w:1800, h:500, d:25). When a user clicks in the middle of the mesh, I want the Point3D of (900, 500, 25)... How can I achieve ...

Editing a xaml icons or images

Is it possible to edit a xaml icons or images in the expression design or using other tools? Is it possible to import a xaml images (that e.g you have exported) in the expression designer for editing?...

WPF: writing smoke tests using ViewModels

I am considering to write smoke tests for our WPF application. The question that I am faced is: should we use UI automation( or some other technology that creates a UI script), or is it good enough to ...

WPF - MVVM - NHibernate Validation

Im facing a bit of an issue when trying to validate a decimal property on domain object which is bound to a textbox on the view through the viewmodel. I am using NHibernate to decorate my property on ...

How do WPF Markup Extensions raise compile errors?

Certain markup extensions raise compile errors. For example StaticExtension (x:Static) raises a compile error if the referenced class cannot be found. Anyone know the mechanism for this? Is it baked ...

WPF design-time context menu

I am trying to create a custom wpf control, I m wondering how I can add some design-time features. I ve googled and can t seem to get to my goal. So here s my simple question, how can I add an entry ...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签