SatisfyImports VS 2010 Designer and Expression Blend Design Data

Apr 4, 2010 at 8:40 PM

I am using SL4 with VS 2010 designer and Expression Blend. When I use SatisfyImports in my constructor and try to view that control in a parent control I get an exception:

Object reference not set to an instance of an object.

 

   at System.ComponentModel.Composition.CompositionInitializer.GetAssemblyList()
   at System.ComponentModel.Composition.CompositionInitializer.CreateCompositionContainer()
   at System.ComponentModel.Composition.Hosting.CompositionHost.TryGetOrCreateContainer(Func`1 createContainer, CompositionContainer& globalContainer)
   at System.ComponentModel.Composition.CompositionInitializer.SatisfyImports(ComposablePart part)
   at System.ComponentModel.Composition.CompositionInitializer.SatisfyImports(Object attributedPart)
   at ScalableCourier.Controls.Client.CompanyOrClientControl..ctor() in C:\PerlLLC\ScalableCourier\ScalableCourier.Controls\Client\CompanyOrClientControl.xaml.cs:line 28

   at System.ComponentModel.Composition.CompositionInitializer.GetAssemblyList()

   at System.ComponentModel.Composition.CompositionInitializer.CreateCompositionContainer()

   at System.ComponentModel.Composition.Hosting.CompositionHost.TryGetOrCreateContainer(Func`1 createContainer, CompositionContainer& globalContainer)

   at System.ComponentModel.Composition.CompositionInitializer.SatisfyImports(ComposablePart part)

   at System.ComponentModel.Composition.CompositionInitializer.SatisfyImports(Object attributedPart)

   at Program.Control..ctor() in C:\Program\Control.xaml.cs:line 28

 

It would be nice if one could set the default import data for when it is being designed.

 

Apr 7, 2010 at 8:32 PM
Edited Apr 7, 2010 at 8:33 PM

What I do jperl, is do a IsInDesigner check before doing a SatisfyImports.

so for example:

if(!System.ComponentModel.DesignerProperties.IsInDesignTool)
      CompositionInitializer.SatisfyImports(this);

 

Later,

Corey Gaudin

Apr 8, 2010 at 1:19 AM

Thanks for the feedback, we are looking into more proper design time support for MEF. The problem is that Blend does not allow the default XAP to be available thus we cannot find the parts. One alternative apporach is to explicitly pass in a set of catalogs for design time by calling CompositionHost.Initialize. You can create a custom class which does this registration and drop it in your app.xaml as a resource.

 

Dec 11, 2010 at 6:29 AM

Hi

could you give more details on how to pass explicity catalogs at design time. I wanna use MEF to provide DesignTime data. Therefore I implemented a custom ComposablePartCatalog which filters exports with the help of an export attribute which simply indicates whether an export is ment to provide design time data. Unfortunately I got stopped by this exception. So could you provide me some hints how I could create those catalogs of design time parts explicity?

Thanks

Jan

Mar 19, 2011 at 1:32 PM

I am currently in the EXACT position.  Of course now using VS2010/silverlight4.  Thanks for your reply glenn, however, I still don't 100% see how this is done in code.  Can you provide details.

bitdisaster, I got as far as you have, did you come up with a resolution?

Mar 19, 2011 at 6:22 PM

I am not sure what you are using mef for. In the case you are using it for viewmodels and data services then you should checkout mefedmvvm. It is an mvvm framework available on codeplex that supports design time data.

On Mar 19, 2011 9:32 AM, "KamelJabber" <notifications@codeplex.com> wrote:
> From: KamelJabber
>
> I am currently in the EXACT position. Of course now using VS2010/silverlight4. Thanks for your reply glenn, however, I still don't 100% see how this is done in code. Can you provide details.bitdisaster, I got as far as you have, did you come up with a resolution?
>
>
Mar 24, 2011 at 11:23 PM

Thanks for your response jperl.  I checked out mefedmvvm; you're right it does support design time data.  I'm using the mvvm light toolkit and an not sure if I want to bring another component into the picture.  After reading a couple of posts from John Popa and couple others, I came up with my own implementation that works well for me.

(adding a custom assembly attribute was the most efficient way to filter out the assemblies I want to load into the designer).  thanks again!

http://mef.codeplex.com/discussions/83308

http://johnpapa.net/silverlight/simple-viewmodel-locator-for-mvvm-the-patients-have-left-the-asylum/

using System;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace MVVMLib
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            if (System.ComponentModel.DesignerProperties.IsInDesignTool)
            {
                var assemblies = typeof(AppDomain).GetMethod("GetAssemblies").Invoke(AppDomain.CurrentDomain, null);

                AggregateCatalog aggCatalog = new AggregateCatalog();
                CompositionContainer Container = new CompositionContainer(aggCatalog);

                if (assemblies != null && assemblies is System.Collections.IEnumerable)
                {
                    foreach (Assembly asm in (assemblies as System.Collections.IEnumerable))
                    {
                        try
                        {
                            var hasVMAttribute = asm.GetCustomAttributes(typeof(HasViewModels), true);

                            if (hasVMAttribute.Count().Equals(0)) continue;

                            aggCatalog.Catalogs.Add(new AssemblyCatalog(asm));
                        }
                        catch (Exception ex) { }
                    }
                }

                Container.ComposeParts(this);
            }
            else
                CompositionInitializer.SatisfyImports(this);
        }

        [ImportMany("ViewModel", AllowRecomposition = true)]
        public IEnumerable<Lazy<object, IViewModelMetadata>> ViewModelsLazy { get; set; }

        [ImportMany("ViewModel", AllowRecomposition = true)]
        public IEnumerable<ExportFactory<object, IViewModelMetadata>> ViewModelsFactories { get; set; }

        private object GetViewModel(string viewModel, bool IsShared = false)
        {
            bool isInDesignMode = System.ComponentModel.DesignerProperties.IsInDesignTool;

            #region -   Try Return Shared   -
            
            if (IsShared)
            {
                var vms = from ef in ViewModelsLazy
                          .Where(v => v.Metadata.Name.Equals(viewModel))
                          select ef;

                if (vms != null)
                {
                    var context = vms.SingleOrDefault(v => v.Metadata.DesignerVM.Equals(isInDesignMode));
                    if (context != null)
                        return context.Value;

                    context = vms.FirstOrDefault();
                    return (context != null) ? context.Value : null;
                }
            }

            #endregion

            #region -   Try Return Non-Sahred   -

            var vmfs = from ef in ViewModelsFactories
                       .Where(ef => ef.Metadata.Name.Equals(viewModel))
                       select ef;

            if (vmfs != null)
            {
                var context = vmfs.SingleOrDefault(v => v.Metadata.DesignerVM.Equals(isInDesignMode));
                if (context != null)
                    return context.CreateExport().Value;

                context = vmfs.FirstOrDefault();
                return (context != null) ? context.CreateExport().Value : null;
            }

            #endregion

            return null;
        }

        public object Find(string viewModel)
        {
            return GetViewModel(viewModel);
        }

        public object FindShared(string viewModel, bool IsShared)
        {
            return GetViewModel(viewModel, IsShared);
        }
    }
}