tags:

views:

1166

answers:

3

I have a winforms App that uses different tabs. I would like to use MEF to be able to add more tabs that are imported at startup. I am having a hard time figuring out how to go about doing this.

Edit: Here is what I did.

I took the main winforms class and striped it down so that there is only a TabControl in it which I expose to each each TabPage through an interface. I then also create a second interface ITab which I use with MEF to get the tabpage and then add it to to the main tabcontrol. To create a new tab page I then just add a new form and then add a tabcontrol to it and design the tab pages. I add the ITab interface to the new form and add the following method which moves the pages to the main form.

public void MoveTabPages(IForm fm)
{
   while (this.tabControl1.Controls.Count > 0)
   {
      fm.tab.Controls.Add(this.tabControl1.Controls[0]);
   }
}

Events delegates and all of that good stuff work as long as they only reference what is in their form class.

Here is the full code.


//Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace Winforms_Mef
{
   public interface IForm
   {
      TabControl tab { get; }
   }

   public interface ITab
   {
      void MoveTabPages(IForm fm);
   }

   public partial class Form1 : Form,IForm
   {
      private CompositionContainer _container;

      [Import]
      public IEnumerable Tabs { get; set; }

      public TabControl tab
      {
         get { return tabControl1; }
      }

      public Form1()
      {
         Compose();
         InitializeComponent();

         foreach (ITab tab in Tabs)
         {
            tab.MoveTabPages(this);
         }

      }

      private void Compose()
      {
         var catalog =new AssemblyCatalog(typeof(ITab).Assembly);
         var batch = new CompositionBatch();
         batch.AddPart(this);

         _container =new CompositionContainer(catalog);
         _container.Compose(batch);
      }
   }
}


//Form2.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Composition;

namespace Winforms_Mef
{
   [Export(typeof(ITab))]
   public partial class Form2 : Form,ITab
   {
      public Form2()
      {
         InitializeComponent();
      }


      public void MoveTabPages(IForm fm)
      {
         while (this.tabControl1.Controls.Count > 0)
         {
            fm.tab.Controls.Add(this.tabControl1.Controls[0]);
         }
      }
   }
}


A: 

Can you give more detail? What type of events do you need to handle? What are your exports/imports? Where did you see MyInitializeComponent()?

Daniel Plaisted
+1  A: 

Before moving on I think your Compose method needs to be cleaned up. Why are you adding the container and catalog into the batch?

batch.AddExportedObject(_container);
batch.AddExportedObject(catalog);

AddExportedObject is used to add a pre-existing object instance as an export and it doesn't make much sense trying to use the container and catalog as exports

privat void Compose()
{
    var catalog =
     new AssemblyCatalog(typeof(ITab).Assembly);

    var batch =
     new CompositionBatch();
    batch.AddPart(this);

    var container =
     new CompositionContainer(catalog);
    container.Compose(batch);
}
TheCodeJunkie
ok but I just copied the Compose from the example code from the Mef site.
Rex Logan
A: 

Here is a version that is generic and allows you swap out your winforms form with another using Mef. There is an IForm interface that is exposed using Mef and it has one method called public void MoveForm(Form form) and it copies the new form over the old form.

Here is the code.



//// Form1 default form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace Winforms_Mef
{
   public interface IForm
   {
      void MoveForm(Form form);
   }

   public partial class Form1 : Form 
   {
      private CompositionContainer _container;

      [Import]
      public IEnumerable Forms { get; set; }

      public Form1()
      {
         Compose();
         InitializeComponent();

         foreach (IForm form in Forms)
         {
            this.SuspendLayout();
            this.Controls.Clear(); // wipe out the current version of the form
            this.ResumeLayout(false);
            form.MoveForm(this);
         }

      }

      private void Compose()
      {
         var catalog = new AssemblyCatalog(typeof(IForm).Assembly);
         var batch = new CompositionBatch();
         batch.AddPart(this);

         _container = new CompositionContainer(catalog);
         _container.Compose(batch);
      }
   }
}

//// Form 2 uses Mef to replace Form1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Composition;

namespace Winforms_Mef
{
   [Export(typeof(IForm))]
   public partial class Form2 : Form,IForm
   {
      public Form2()
      {
         InitializeComponent();
      }


      public void MoveForm(Form form)
      {
         this.SuspendLayout();
         form.SuspendLayout();

         form.AutoScaleDimensions = this.AutoScaleDimensions;
         form.AutoScaleMode=this.AutoScaleMode;
         form.ClientSize=this.ClientSize;
         form.Name=this.Name;
         form.Text=this.Text;
         while (this.Controls.Count > 0)
         {
            form.Controls.Add(this.Controls[0]);
         }

         this.ResumeLayout(false);
         form.ResumeLayout(false);
      }
   }
}



Rex Logan