Using MEF in controls instantiated from XAML

自古美人都是妖i 提交于 2019-12-12 10:49:24

问题


I have a UserControl I've created which imports several parts using the [Import] attribute.

public class MyUserControl : UserControl, IPartImportsSatisfiedNotification
{
    [Import]
    public IService Service { get; set; }

    public MyUserControl()
    {
    }

    public void OnImportsSatisfied()
    {
        // Do something with Service.
    }
}

This UserControl is instantiated from XAML, so its imports aren't being satisfied and OnImportsSatisfied isn't being called.

<local:MyUserControl />

My question is how can I satisfy my class's imports when it's being created in XAML.


回答1:


From MSDN:

To be instantiated as an object element in XAML, a custom class must meet the following requirements:
The custom class must be public and must expose a default (parameterless) public constructor. (See following section for notes regarding structures.)
The custom class must not be a nested class. The extra "dot" in the full-name path makes the class-namespace division ambiguous, and interferes with other XAML features such as attached properties.
If an object can be instantiated as an object element, the created object can fill the property element form of any properties that take the object as their underlying type.
You can still provide object values for types that do not meet these criteria, if you enable a value converter. For more information, see Type Converters and Markup Extensions for XAML.

From there, you have two choices:
1) Using a TypeConverter:
Using a type converter will allow you to instantiate an object without a parameterless constructor, but you will have to provide a TypeConverter that will do the instantiation.

Now, I never had to use it, I cannot help you further with that.

2) Retrieve IService using the ServiceLocator:

public class MyUserControl : UserControl
{    
    public IService Service { get; set; }

    public MyUserControl()
    {
       Service = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IService>();
       // You can do something with Service here already.
    }
}

I realize it is a change in the design of your class, but hopefully you can cope with it.

Hope this helps,

Bab.




回答2:


if you did not want mef to create your usercontrol, you have to use the compositioncontainer in your usercontrol and call GetExport direct. but then you have the problem to get the instance of your compositioncontainer :)

ps: i let mef create my wpf views in my applications.




回答3:


(I'm resurrecting this in case anyone comes across it. As a disclaimer, I'm no expert and these are just solutions I found to be working.)

I found that calling CompositionContainer.ComposeParts(myUserControl) works. I call this on the control's constructor. You'll need to get a reference to the CompositionContainer somehow:

public MyUserControl()
{
    compositionContainer.ComposeParts(this);
}

Additional solution:

This is probably unnecessary, but here's another way. This is far more convoluted but it does allow you to "Import" your usercontrol in XAML.

To have your imports satisfied, MyUserControl needs to be exported and then instantiated by MEF. My solution was to have static field in a class that holds a "Locator" object. This Locator object is responsible for importing and returning exported objects. Then I could refer to this static field in XAML, like so:

<ContentControl Content="{Binding MyUserControl, Source={x:Static v:SomeClass.Locator}}">

SomeClass has a static property called Locator which gets assigned early in the application's life cycle. The Locator could then have a MyUserControl property that gets Imported.


(Disclaimer: the links below are to my own framework and the solution, being as crude as it is, if used should be used with care.)

To provide an example of the above, I'll explain how I implemented it in my framework:

In my case, SomeClass is a subclass of System.Windows.Application that replaces App.xaml, and ViewLocator is assigned on its OnStartup, as can be seen here.

The ViewLocator class is a System.Dynamic.DynamicObject that imports views, which have a custom ViewExport attribute. Views are identified using the ViewExportAttribute.Alias property.

This is an example of a view being exported and being assigned an alias.

Finally, the MEF instantiated instance of the view can be used in XAML as follows:

<ContentControl Content="{Binding HomeView, Source={x:Static v:FrameworkApp.ViewLocator}}">



来源:https://stackoverflow.com/questions/8667983/using-mef-in-controls-instantiated-from-xaml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!