MEF composition with multiple interdependent parts

184 views Asked by At

What is the best way to design an MEF-based plugin architecture that has dependencies between plugins? For example:

  class MainForm
  {
    CompositionContainer container;

    [ImportMany]
    IEnumerable<Lazy<IWindow>> windows;

    public MainForm()
    {
      this.container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
      this.container.ComposeParts(this);
    }

    public void DoSomething()
    {
      foreach (var winPart in windows)
      {
        Debug.WriteLine(winPart.Value.Name);
      }
    }
  }


  interface IWindow
  {
    string Name { get; }
  }

  delegate void AnEvent(object sender, EventArgs e);
  interface IEventManager
  {
    event AnEvent AnEvent;
    void OnAnEvent(object sender, EventArgs eventArgs);
  }

  [Export(typeof(IEventManager))]
  class EventManager : IEventManager
  {
    public event AnEvent AnEvent = delegate { };
    public void OnAnEvent(object sender, EventArgs eventArgs) { AnEvent(sender, eventArgs); }
  }

  [Export(typeof(IWindow))]
  class Window1 : IWindow
  {
    [Import]
    IEventManager eventMgr;

    public Window1() { }

    public string Name
    {
      get
      {
        eventMgr.OnAnEvent(this, new EventArgs());
        return "Window1";
      }
    }
  }

  [Export(typeof(IWindow))]
  class Window2 : IWindow
  {
    [Import]
    IEventManager eventMgr;

    public Window2()  {  this.eventMgr.AnEvent += eventMgr_AnEvent; }

    void eventMgr_AnEvent(object sender, EventArgs e)
    {
      Debug.WriteLine("Event from Window 2");
    }

    public string Name { get { return "Window2"; } }
  }

In the Window2 constructor this.eventMgr is null. I would expect it to be composed by MainForm. One approach is to have multiple CompositionContainers but if you do that there are two instances of EventManager rather than one shared instance. What would be the best way of doing this?

1

There are 1 answers

0
LucasMcGraw On BEST ANSWER

In exploring this question more, inter-dependencies are perfectly allowed. The key is to have the assemblies available in the catalog passed to the CompositionContainer that is being used to compose the parts. Then the following code helped in allowing one plugin to access another plugin:

  [Export(typeof(IWindow))]
  class Window2 : IWindow
  {
    IEventManager eventMgr;

    [ImportingConstructor]
    public Window2([Import(typeof(IEventManager))]IEventManager mgr)
    {
      this.eventMgr.AnEvent += eventMgr_AnEvent;
    }

    void eventMgr_AnEvent(object sender, EventArgs e)
    {
      Debug.WriteLine("Event from Window 2");
    }

    public string Name { get { return "Window2"; } }
  }