Implementing IComposer and Adding xap Dinamically

Aug 26, 2010 at 5:00 PM

Sorry Me again, i wanted to open a new Discussion becuase i think make some more sense.

So I want to Download xap files depending on navigation request

So I got something like that

 CatalogService.AddXap( XAPNAME + ".xap", CatalogDownloadCompleted);

 

 void CatalogDownloadCompleted(AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

....
            var usercontrol = module.Value;
             ContentControl.Content = usercontrol;
        }

then I want MEFedMVVM's container to be merged with my main container that also will have the parts of the rest of xaps downloaded.

So my DeploymentCatalogService looks like that

[Export(typeof(IDeploymentCatalogService))]
    public class DeploymentCatalogService : IDeploymentCatalogService, IComposer
    {
        private static AggregateCatalog _aggregateCatalog;

        Dictionary<string, DeploymentCatalog> _catalogs;

        public DeploymentCatalogService()
        {
            _catalogs = new Dictionary<string, DeploymentCatalog>();
        }

        public static void Initialize()
        {
            _aggregateCatalog = new AggregateCatalog();
            _aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
            CompositionHost.Initialize(_aggregateCatalog);
        }

        public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
        {
            DeploymentCatalog catalog;
            if (!_catalogs.TryGetValue(uri, out catalog))
            {
                catalog = new DeploymentCatalog(uri);
                if (completedAction != null)
                    catalog.DownloadCompleted += (s, e) => completedAction(e);
                else
                    catalog.DownloadCompleted += catalog_DownloadCompleted;

                catalog.DownloadAsync();
                _catalogs[uri] = catalog;
                _aggregateCatalog.Catalogs.Add(catalog);
            }
        }

        void catalog_DownloadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
                throw e.Error;
        }

        public void RemoveXap(string uri)
        {
            DeploymentCatalog catalog;
            if (_catalogs.TryGetValue(uri, out catalog))
            {
                _aggregateCatalog.Catalogs.Remove(catalog);
            }
        }

        #region IComposer Members

        public IEnumerable<ExportProvider> GetCustomExportProviders()
        {
            return null;
        }

        public ComposablePartCatalog InitializeContainer()
        {
            return _aggregateCatalog;
        }

        #endregion
    }

So I am implementing IComposer but still the app is not recomposing, any idea ?

 

Aug 26, 2010 at 5:18 PM

I have this in my view

xmlns:meffed="http:\\www.codeplex.com\MEFedMVVM"
meffed:ViewModelLocator.NonSharedViewModel="NewIssueListViewModel"

and this on my view model

[ExportViewModel("NewIssueListViewModel")]
public class NewIssueListViewModel: NotifyPropertyChangedBase

But even having that I am getting this error when the user control that is coming from the another xap is retrieved and pushed to the UI e.g. ContentControl.Content = usercontrol; so when the view gets to InitializeComponent failed on this.

No valid exports were found that match the constraint '((((exportDefinition.ContractName == "NewIssueListViewModel") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Object".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity")))) AndAlso (((exportDefinition.Metadata.ContainsKey("Name") AndAlso System.String.IsInstanceOfType(exportDefinition.Metadata.get_Item("Name"))) AndAlso exportDefinition.Metadata.ContainsKey("IsDataContextAware")) AndAlso System.Boolean.IsInstanceOfType(exportDefinition.Metadata.get_Item("IsDataContextAware")))) AndAlso ((Not(exportDefinition.Metadata.ContainsKey("System.ComponentModel.Composition.CreationPolicy")) OrElse Any.Equals(exportDefinition.Metadata.get_Item("System.ComponentModel.Composition.CreationPolicy"))) OrElse NonShared.Equals(exportDefinition.Metadata.get_Item("System.ComponentModel.Composition.CreationPolicy"))))', invalid exports may have been rejected.

Aug 26, 2010 at 5:33 PM

Ok the path in which the app is failing is ViewModelLocator -> AttachViewModel(FrameworkElement element, string vmContractName, CreationPolicy policy) -> ViewModelRepository (AttachViewModelToView( string vmContract, FrameworkElement view, CreationPolicy policy) -> var vmExport = Instance.Resolver.GetViewModelByContract(vmContract, view, policy);

then Errors

 

No valid exports were found that match the constraint '((((exportDefinition.ContractName == "NewIssueListViewModel") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Object".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity")))) AndAlso (((exportDefinition.Metadata.ContainsKey("Name") AndAlso System.String.IsInstanceOfType(exportDefinition.Metadata.get_Item("Name"))) AndAlso exportDefinition.Metadata.ContainsKey("IsDataContextAware")) AndAlso System.Boolean.IsInstanceOfType(exportDefinition.Metadata.get_Item("IsDataContextAware")))) AndAlso ((Not(exportDefinition.Metadata.ContainsKey("System.ComponentModel.Composition.CreationPolicy")) OrElse Any.Equals(exportDefinition.Metadata.get_Item("System.ComponentModel.Composition.CreationPolicy"))) OrElse NonShared.Equals(exportDefinition.Metadata.get_Item("System.ComponentModel.Composition.CreationPolicy"))))', invalid exports may have been rejected.

Aug 27, 2010 at 12:20 PM

Close thi, sorted

the last line solved the issue   LocatorBootstrapper.ApplyComposer(this);

 public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
        {
            DeploymentCatalog catalog;
            if (!_catalogs.TryGetValue(uri, out catalog))
            {
                catalog = new DeploymentCatalog(uri);
                if (completedAction != null)
                    catalog.DownloadCompleted += (s, e) => completedAction(e);
                else
                    catalog.DownloadCompleted += catalog_DownloadCompleted;

                catalog.DownloadAsync();
                _catalogs[uri] = catalog;
                _aggregateCatalog.Catalogs.Add(catalog);
                LocatorBootstrapper.ApplyComposer(this);
            }
        }

 

Thanks for your help

 

 

Sep 28, 2010 at 2:45 AM

Hi I am getting the same error:

Error while resolving ViewModel. System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '(((exportDefinition.ContractName == "DAAProgramVM") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Object".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity")))) AndAlso (((exportDefinition.Metadata.ContainsKey("Name") AndAlso System.String.IsInstanceOfType(exportDefinition.Metadata.get_Item("Name"))) AndAlso exportDefinition.Metadata.ContainsKey("IsDataContextAware")) AndAlso System.Boolean.IsInstanceOfType(exportDefinition.Metadata.get_Item("IsDataContextAware"))))', invalid exports may have been rejected.   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)   at MEFedMVVM.ViewModelLocator.MEFedMVVMExportProvider.GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1& exports)   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1& exports)   at System.ComponentModel.Composition.Hosting.AggregateExportProvider.GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1& exports)   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1& exports)   at System.ComponentModel.Composition.Hosting.CompositionContainer.GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1& exports)   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition)   at MEFedMVVM.ViewModelLocator.MEFedMVVMResolver.GetViewModelByContract(String vmContractName, Object contextToInject, CreationPolicy policy)   at MEFedMVVM.ViewModelLocator.ViewModelRepository.AttachViewModelToView(String vmContract, FrameworkElement view, CreationPolicy policy)   at MEFedMVVM.ViewModelLocator.ViewModelLocator.AttachViewModel(FrameworkElement element, String vmContractName, CreationPolicy policy)

I've added the LocatorBootstrapper.ApplyComposer to my DeploymentCatalogService but still has issues. How do I dynamically load a XAP into the View of my main project (using MefedMVVM) where the XAP contains a usercontrol + viewmodel which also is using MefedMVVM?

Coordinator
Sep 28, 2010 at 8:55 AM

can you show me your Composer and were you are putting LocatorBootstrapper.ApplyComposer

Sep 28, 2010 at 9:32 AM
Edited Sep 28, 2010 at 11:51 AM

Hi all, me too :-).

 

Similar scenario here, but slightly different problem - I can't seem to get MEF recomposition working in a ViewModel imported via MEFedMVVM's ViewModelLocator.

 

To be precise, the application I'd like to build looks like this

- the MainView imports a MainViewModel via MEFedMVVM's ViewModelLocator

- the MainViewModel contains a recomposable Collection<Lazy<UserControl, IMyPlugin>> of Plugin-UserControls

- an external xap exports one or more UserControls via an ExportPluginAttribute that is based on IMyPlugin Metadata

- each of the Plugin-UserControls in turn imports an associated ViewModel via the ViewModelLocator

- the external xap is pulled in on demand via a DeploymentCatalogService (including an implementation of IComposer and a call to LocatorBootstrapper.ApplyComposer along the lines of acosta's post above)

What I'm experiencing in this scenario is that a Plugin-UserControl defined in the application's main xap is included in the composed Collection<...> at application startup time, but the external Plugin-UserControl is not included - in fact a recomposition does not appear to happen.

If I place the recomposable Collection<...> in a MainViewModel that is manually attached to its MainView the recomposition works allright and I'm even able to instantiate the Plugin-UserControls (both locally defined and the ones from the external xap) without an Exception.

 

I'd be happy to provide a simple repro-solution that shows two views side by side, a conventional View-ViewModel pair where recomposition on external load works and a MEFedMVVM View-ViewModel pair where it doesn't work.

 

Regards, DrJ

Sep 28, 2010 at 10:28 AM

my situation is very similar to the above - except the only way I could get it working was to not use MEFedMVVM in the imported XAP controls.

 

[Export(typeof(IDeploymentCatalogService))]
    public class DeploymentCatalogService : IDeploymentCatalogService
    {
        private static AggregateCatalog _aggregateCatalog;

        readonly Dictionary<string, DeploymentCatalog> _catalogs;

        public DeploymentCatalogService()
        {
            _catalogs = new Dictionary<string, DeploymentCatalog>();
        }

        public static void Initialize()
        {
            _aggregateCatalog = new AggregateCatalog();
            _aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
            //_aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ViewModelLocator).Assembly));
            //_aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(App).Assembly));

            //LocatorBootstrapper.ApplyComposer(this);
            //var mainCompositionContainer = LocatorBootstrapper.EnsureLocatorBootstrapper();
            CompositionHost.Initialize(_aggregateCatalog);
        }

        public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
        {
            DeploymentCatalog catalog;
            if (!_catalogs.TryGetValue(uri, out catalog))
            {
                catalog = new DeploymentCatalog(uri);
                if (completedAction != null)
                    catalog.DownloadCompleted += (s, e) => completedAction(e);
                else
                    catalog.DownloadCompleted += CatalogDownloadCompleted;

                catalog.DownloadAsync();
                _catalogs[uri] = catalog;
                _aggregateCatalog.Catalogs.Add(catalog);

                LocatorBootstrapper.ApplyComposer(this);
            }
            //_aggregateCatalog.Catalogs.Add(catalog);
        }

        static void CatalogDownloadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }
        }

        public void RemoveXap(string uri)
        {
            DeploymentCatalog catalog;
            if (_catalogs.TryGetValue(uri, out catalog))
            {
                _aggregateCatalog.Catalogs.Remove(catalog);
                //_catalogs.Remove(uri);
            }
        }

        public int Count()
        {
            return _aggregateCatalog.Catalogs.Count;
        }

        public ComposablePartCatalog InitializeContainer()
        {
            return _aggregateCatalog;
        }

        public IEnumerable<ExportProvider> GetCustomExportProviders()
        {
            return null;
        }
    }

My imported collection inside the view is like so

[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IProgramMetadata>[] Programs { get; set; }
These UserControls (Programs) are added to the View dynamically based on URI navigation. The Views will come up OK but it won't find the ViewModel to attach.

 

Sep 28, 2010 at 10:42 AM

That is my implementation.

namespace BNPP.IssueMaster.Controller
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition.Primitives;
    using MEFedMVVM.ViewModelLocator;

    [Export(typeof(IDeploymentCatalogService))]
    public class DeploymentCatalogService : IDeploymentCatalogService, IComposer
    {
        private static AggregateCatalog aggregateCatalog;

        private Dictionary<string, DeploymentCatalog> catalogs;

        public DeploymentCatalogService()
        {
            catalogs = new Dictionary<string, DeploymentCatalog>();
        }

        public static void Initialize()
        {
            aggregateCatalog = new AggregateCatalog();
            aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
            CompositionHost.Initialize(aggregateCatalog);
        }

        public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction)
        {
            DeploymentCatalog catalog;
            if (!catalogs.TryGetValue(uri, out catalog))
            {
                catalog = new DeploymentCatalog(uri);
                if (completedAction != null)
                {
                    catalog.DownloadCompleted += (s, e) => completedAction(e);
                }
                else
                {
                    catalog.DownloadCompleted += CatalogDownloadCompleted;
                }

                catalog.DownloadAsync();
                catalogs[uri] = catalog;
                aggregateCatalog.Catalogs.Add(catalog);
                LocatorBootstrapper.ApplyComposer(this);
            }
        }

        private void CatalogDownloadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }
        }

        public void RemoveXap(string uri)
        {
            DeploymentCatalog catalog;
            if (catalogs.TryGetValue(uri, out catalog))
            {
                aggregateCatalog.Catalogs.Remove(catalog);
            }
        }

        #region IComposer Members

        public IEnumerable<ExportProvider> GetCustomExportProviders()
        {
            return null;
        }

        public ComposablePartCatalog InitializeContainer()
        {
            return aggregateCatalog;
        }

        #endregion
    }
}

Sep 28, 2010 at 11:48 AM
Edited Sep 28, 2010 at 11:56 AM

Ok, I'll take my shot at showing off the DeploymentCatalogService implementation of the day as well :-).

According to Marlon's remark

"you can call the ApplyComposer method of the LocatorBootstrapper and inject a runtime composer that you implement. You must make sure to make this call before anything gets composed."

in How does MEFedMVVM compose the catalogs and how can I override the behavior? – MEFedMVVM Part 4 I decided to put the call to LocatorBootstrapper.ApplyComposer() right into the constructor. Seems to work out well so far - except for recomposition in ViewModels imported via ViewModelLocator :-(.

I'm suspecting that the root of my recomposition problem maybe doesn't lie in the DeploymentCatalogService itself - could it be related to the order of initialization of the DeploymentCatalogService, some elusive MEFedMVVM component (ViewModelLocator?), and the first occurrence of a MEF composition?

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

using MEFedMVVM.ViewModelLocator;

namespace MEFDeploymentTest
{
   [Export(typeof(IDeploymentCatalogService))]
   public class DeploymentCatalogService : IDeploymentCatalogServiceIComposer
   {
      #region Members

      private static AggregateCatalog aggregateCatalog;

      private Dictionary<stringDeploymentCatalog> catalogs = new Dictionary<stringDeploymentCatalog>();

      #endregion

      #region private Methods

      private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
      {
         if (e.Error != null)
            throw e.Error;
      }

      #endregion

      #region Constructors

      public DeploymentCatalogService()
      {
         LocatorBootstrapper.ApplyComposer(this);
      }

      #endregion

      #region public Methods

      public static void Initialize()
      {
         aggregateCatalog = new AggregateCatalog();
         aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
         CompositionHost.Initialize(aggregateCatalog);
      }

      #endregion

      #region IDeploymentCatalogService Members

      public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
      {
         DeploymentCatalog catalog;
         if (!catalogs.TryGetValue(uri, out catalog)) {
            catalog = new DeploymentCatalog(uri);

            if (completedAction != null)
               catalog.DownloadCompleted += (sender, args) => completedAction(args);
            else
               catalog.DownloadCompleted += DownloadCompleted;

            catalog.DownloadAsync();
            catalogs[uri] = catalog;
            aggregateCatalog.Catalogs.Add(catalog);
            OnCatalogsChanged();
         }
      }

      public bool ContainsXap(string uri)
      {
         return catalogs.ContainsKey(uri);
      }

      public void RemoveXap(string uri)
      {
         DeploymentCatalog catalog;
         if (catalogs.TryGetValue(uri, out catalog)) {
            aggregateCatalog.Catalogs.Remove(catalog);
            catalogs.Remove(uri);
         }
      }

      protected virtual void OnCatalogsChanged()
      {
         EventHandler handler = CatalogsChanged;
         if (handler != null)
            handler(thisEventArgs.Empty);
      }

      public event EventHandler CatalogsChanged;

      #endregion

      #region IComposer Members

      public IEnumerable<ExportProvider> GetCustomExportProviders()
      {
         return null;
      }

      public ComposablePartCatalog InitializeContainer()
      {
         return aggregateCatalog;
      }

      #endregion
   }
}
Sep 28, 2010 at 12:20 PM
Edited Sep 28, 2010 at 12:21 PM

Additional finding: It appears that Marlon's remark regarding the requirement of calling LocatorBootstrapper.ApplyComposer() before the first MEF composition must be taken seriously.

Context: My DeploymentCatalogService implementation as shown above.

Scenario1: A DeploymentCatalogService instance is created in App.cs and passed into the MainPageViewModel via the MainPage.
Result: Everything works as required.

Scenario2: A DeploymentCatalogService instance is injected into the MainPageViewModel via an [ImportingConstructor].
Consequence: LocatorBootstrapper.ApplyComposer() is being called after the first MEF composition, namely that of the DeploymentCatalogService itself.
Result: The Exception witnessed by ravinator is thrown.

QED

Remains to answer the question why MEF recomposition works in a contained UserControl when its ViewModel/DataContext is explicitely set and doesn't work for an otherwise identical UserControl when its DataContext is composed via ViewModelLocator. The composition in the latter case should come after DeploymentCatalogService initialization and the call to LocatorBootstrapper.ApplyComposer(), right?

Coordinator
Sep 29, 2010 at 7:56 AM
the call to LocatorBootstrapper.ApplyComposer(this); must be done in the APP.xaml at startup of the app if not then MEFedMVVM will assume you want to use the default i.e only the current XAP. 

I did not understand the question
"Remains to answer the question why MEF recomposition works in a contained UserControl when its ViewModel/DataContext is explicitely set and doesn't work for an otherwise identical UserControl when its DataContext is composed via ViewModelLocator. The composition in the latter case should come after DeploymentCatalogService initialization and the call to LocatorBootstrapper.ApplyComposer(), right?"
Sep 29, 2010 at 8:52 PM
marlongrech wrote:
the call to LocatorBootstrapper.ApplyComposer(this); must be done in the APP.xaml at startup of the app if not then MEFedMVVM will assume you want to use the default i.e only the current XAP. 

I did not understand the question
"Remains to answer the question ..."

Ok, let me rephrase my question.

Even though I call LocatorBootstrapper.ApplyComposer(this) first thing in the application I still have the same problem described above in post #7 which is:

I'd like to use on-demand composition of UserControls from a set of extension XAPs.
If I place my Collection<Lazy<UserControl, IMyPlugin>> - properly annotated with [ImportMany(AllowRecomposition = true)] - in a ViewModel that I manually instantiate and assign to its View's DataContext property in the View constructor, then MEF recomposition works as soon as the extension XAPs are loaded via the DeploymentCatalogService.
I can then go on and instantiate the Plugin-UserControls - all is well.
If, on the other hand, I place the very same Collection<Lazy<UserControl, IMyPlugin>> - equally annotated with [ImportMany(AllowRecomposition = true)] - in an identical ViewModel that is injected into the MainPage's DataContext via the ViewModelLocator (from XAML), then the Collection<Lazy<...>> remains unchanged when the extension XAPs are loaded via the DeploymentCatalogService.

I have a simple .sln with two UserControls arranged side by side where one has an explicitely instantiated and assigned ViewModel (VM_explicit) and the other one a ViewModelLocator-injected ViewModel (VM_injected). Both ViewModels are identical but for the [ExportViewModel] declaration and each contains a Collection<Lazy<UserControl, IMyPlugin>> annotated with the required [ImportMany(AllowRecomposition = true)].
The call to LocatorBootstrapper.ApplyComposer(this) is executed before the initialization for the application's MainPage - in the constructor of a DeploymentCatalogService as described above.
Now this DeploymentCatalogService instance is called to AddXap(...) two extension-XAPs each containing two exports for Plugin-UserControls (with a matching ExportAttribute declaration).
The resulting MEF recomposition results in only the ViewModels VM_explicit getting its Collection<Lazy<...>> updated with four new items while the Collection<Lazy<...>> in VM_injected remains unchanged.

My expectation after the discussion above would have been that - once the DeploymentCatalogService instance has been disclosed to the LocatorBootstrapper - all Imports performed through this DeploymentCatalogService instance would lead to a recomposition in every matching import.

I'd be grateful for any advice as to how I can use your excellent framework for ViewModel injection and still have MEF recomposition for on-demand loaded extension XAPs.

I'd be happy to send the above mentioned simple .sln to you to illustrate my problem.

 

Coordinator
Sep 30, 2010 at 5:24 AM

Send me the solution please and I will have a look 

Sep 30, 2010 at 1:20 PM

Can you please post any finding here because I am encountering the same issues

Sep 30, 2010 at 2:56 PM

Actually I just implemented the modified DeploymentCatalogService as posted by DrJ and my ViewModels (inside the imported XAPs) are importing OK!

Another thing - I didn't need to pass the instance of DeploymentCatalogService anywhere. I just needed to create it inside App.xaml and Import as normal to where it was required.

        public App()
        {
            Startup += ApplicationStartup;
            Exit += ApplicationExit;
            UnhandledException += ApplicationUnhandledException;

            var deploymentCatalogService = new DeploymentCatalogService();
            DeploymentCatalogService.Initialize();

            InitializeComponent();            
        }
However, I now have another issue. I am using the Cinch framework and I would like to Import the IMessageBoxService that is created in the main XAP inside the Imported XAPs. Is this possible?
I am getting the following error:
More than one export was found that matches the constraint '((exportDefinition.ContractName == "Cinch.IMessageBoxService") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "Cinch.IMessageBoxService".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))'.
Oct 1, 2010 at 9:32 AM
Edited Oct 1, 2010 at 9:34 AM
marlongrech wrote:

Send me the solution please and I will have a look 

I just uploaded my repro-solution as issue 14355.

Oct 1, 2010 at 11:33 AM
Further analysis leads me to believe that my problem of not getting [Imports] recomposed in a ViewModel attached via the MEFedMVVM ViewModelLocator on loading new ComposableParts via a DeploymentCatalogService may be due to a bug in the MEF implementation of CatalogExportProvider.
To me it looks as though only the Changing-Event of an INotifyComposablePartCatalogChanged passed into the CatalogExportProvider() constructor is being connected to the CatalogExportProvider while the corresponding Changed-Event is left disconnected.
Could this lead to the attached [Imports] of an injected ViewModel not being notified of recompositions?

From System.ComponentModel.Composition.Hosting.CompositionContainer via Reflector:

      public CatalogExportProvider(ComposablePartCatalog catalog, bool isThreadSafe)
      {
         this._activatedParts = new Dictionary<ComposablePartDefinitionComposablePart>();
         this._rejectedParts = new HashSet<ComposablePartDefinition>();
         this._conditionalReferencesForRecomposableParts = new ConditionalWeakTable<objectList<ComposablePart>>();
         this._partsToDispose = new HashSet<IDisposable>();
         this._isDisposed = false;
         this._isRunning = false;
         Requires.NotNull<ComposablePartCatalog>(catalog, "catalog");
         this._catalog = catalog;
         INotifyComposablePartCatalogChanged changed = this._catalog as INotifyComposablePartCatalogChanged;
         if (changed != null) {
            changed.Changing += new EventHandler<ComposablePartCatalogChangeEventArgs>(this.OnCatalogChanging);
         /* This is where I suspect the following line is missing:
         changed.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>(this.OnCatalogChanged);
         */
         }
         this._lock = new CompositionLock(isThreadSafe);
      }
Coordinator
Oct 2, 2010 at 11:58 AM

Dr J lets move this discussion to the issue you opened.

ravinator

Yes it is possible... when you are creating the aggregate catalog add the assembly of Cinch... i.e 

 

aggregateCatalog = new AggregateCatalog();        

aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ViewModelLocator).Assembly)); // add meffedmvvm        

aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(DeploymentCatalogService).Assembly)); // add this assembly        

aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(IMessageBoxService).Assembly)); // add the Cinch assembly        

CompositionHost.Initialize(aggregateCatalog);

Coordinator
Oct 2, 2010 at 11:58 AM

by the way sorry for the slow responses but right now I am slammed with a project at work 

Oct 4, 2010 at 1:16 AM

Hi marlongrech thanks I added those assemblies as you specified which fixed up my issues there. But now I'm getting the same error for all my ViewModels:

I shouldn't need to add the assemblies for my ViewModels as well do I? 

A first chance exception of type 'System.ComponentModel.Composition.ImportCardinalityMismatchException' occurred in System.ComponentModel.Composition
Error while resolving ViewModel. System.ComponentModel.Composition.ImportCardinalityMismatchException: More than one export was found that matches the constraint '(((exportDefinition.ContractName == "PatientViewModel") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Object".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity")))) AndAlso (((exportDefinition.Metadata.ContainsKey("Name") AndAlso System.String.IsInstanceOfType(exportDefinition.Metadata.get_Item("Name"))) AndAlso exportDefinition.Metadata.ContainsKey("IsDataContextAware")) AndAlso System.Boolean.IsInstanceOfType(exportDefinition.Metadata.get_Item("IsDataContextAware"))))'.