tags:

views:

254

answers:

1

Hi,

I'm trying to build a WPF application using MEF and MVVM. I'm exporting my ViewModel but I want my ViewModels to accept a Model parameter in the constructor: I will create a specific Model and supply it to ViewModel's constructor. I've tried to understand how ImportingConstructorAttribute works, it seems like it is the way to have a customized constructor. But I couldn't figure out how to use it.

Can somebody give a working example on using ImportingConstructorAttribute?

Thanks in advance

+4  A: 

Here you go. The class Test imports an IFoo instance via the constructor:

   public class Program
   {
      public static void Main(string[] args)
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         var container = new CompositionContainer(catalog);
         Test test = container.GetExportedValue<Test>();
      }
   }

   [Export]
   public class Test
   {
      private IFoo foo;

      [ImportingConstructor]
      public Test(IFoo foo)
      {
         this.foo = foo;
      }
   }

   public interface IFoo
   {
   }

   [Export(typeof(IFoo))]
   public class Foo : IFoo
   {
   }

edit in response to comment: I assume that by "initialized by us not a shared one" you mean that you want to manually instantiate a non-attributed, non-MEF class and inject it as a dependency for a MEF part. Typically you would do that like this:

   public class Program
   {
      public static void Main(string[] args)
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         var container = new CompositionContainer(catalog);

         // create and add non-MEF instance explicitly to container
         var nonMEF = new NonMefClass();
         container.ComposeExportedValue<IFoo>("Test.foo", nonMEF);

         Test test = container.GetExportedValue<Test>();
      }
   }

   [Export]
   public class Test
   {
      private IFoo foo;

      [ImportingConstructor]
      public Test([Import("Test.foo", typeof(IFoo))] IFoo foo)
      {
         this.foo = foo;
      }
   }

   public interface IFoo
   {
   }
   public class NonMefClass : IFoo
   {
   }

An alternative to adding instances explicitly to the container with ComposeExportedValue is to use a property export. You can then initialize a non-MEF object as you want in a property getter:

   public class Bar
   {
      [Export("Test.foo", typeof(IFoo))]
      public IFoo Foo
      {
         get
         {
            return new NonMefClass();
         }
      }
   }

edit in response to comment2: First a warning; ImportingConstructor and PartCreator don't seem to play well together in MEF preview 8, probably because PartCreator is just a sample which is not yet well tested. Use property injection for importing PartCreator instances.

Now to answer your question; if you just want to force MEF to create multiple instances of a dependency then you just need to attribute the import a [Import("Test.foo", typeof(IFoo), RequiredCreationPolicy=CreationPolicy.NonShared)].

If you are after completely different compositions for each instance, then things are a bit more complex. You can't really have a single part (i.e. a class with MEF attributes) and have it composed differently for different part instances unless you set up multiple containers. Instead, what I do in such cases is to create multiple parts that inherit from a common class. You then have 1 subclass for each desired composition:

   public class Test
   {
      private IFoo foo;

      public Test(IFoo foo)
      {
         this.foo = foo;
      }
   }

   [Export]
   public class TestComposition1 : Test
   {   
      [ImportingConstructor]
      public Test([Import("TestComposition1.foo", typeof(IFoo))] IFoo foo)
         : base(foo)
      {
      }
   }

   [Export]
   public class TestComposition2 : Test
   {   
      [ImportingConstructor]
      public Test([Import("TestComposition2.foo", typeof(IFoo))] IFoo foo)
         : base(foo)
      {
      }
   }

This of course requires that you have a limited number of alternative compositions in mind. If the number of desired compositions cannot be enumerated at design time, you need more complex stuff, probably involving PartCreator and dynamic selection based on part metadata.

Wim Coenen
Hi,Thanks for the reply. Here the Test class imports a shared Foo instance in constructor. Am I right? What I'm asking is whether we can give a specific Foo that is initialized by us not a shared one? Is this possible?
canxss
Thanks for the detailed answer. But I'm using PartCreater in DynamicInstantiation sample in MEF Beta 2 in order to create more than one Test class. So each test class will have different foos created for them.The first example, using the container explicitly doesn't fit at all to my situation. The second one is much better but I don't know how I can use it in my "more than one instance" case.
canxss
Thanks again for the reply. After your explanation I decided to quit having a parameterized CTOR. As you said PartCreator is still new and I don't want unexpected results.
canxss
If it works for you then no need to worry, but in my case I consistently got unexpected exceptions during composition as soon as I imported PartCreator via the constructor...
Wim Coenen