【问题标题】:Using MEF in controls instantiated from XAML在从 XAML 实例化的控件中使用 MEF
【发布时间】:2011-12-29 12:39:24
【问题描述】:

我创建了一个 UserControl,它使用 [Import] 属性导入多个部分。

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

    public MyUserControl()
    {
    }

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

这个 UserControl 是从 XAML 实例化的,因此它的导入没有得到满足,OnImportsSatisfied 也没有被调用。

<local:MyUserControl />

我的问题是当我的类在 XAML 中创建时,我如何才能满足它的导入。

【问题讨论】:

  • 这可能很难做到,因为 WPF 通常会卸载不可见的控件,因此该控件可能只存在一次,但可能会多次加载和卸载。
  • @Rachel 为了防止这种情况,他可以使用延迟加载。
  • 您确定这是正确的做法吗?这看起来像您正在尝试将业务逻辑放入 UI 控件中。这总是坏事。
  • @Euphoric 我同意,逻辑应该在 MyUserControl 的 ViewModel 中。尽管如此,问题仍然存在。

标签: c# .net wpf xaml mef


【解决方案1】:

来自 MSDN:

要在 XAML 中实例化为对象元素,自定义类必须 满足以下要求:
自定义类必须是公共的,并且必须公开一个默认(无参数)公共构造函数。 (请参阅以下部分的注释 关于结构。)
自定义类不能是嵌套类。全名路径中额外的“点”使类命名空间划分不明确,并且 会干扰其他 XAML 功能,例如附加属性。
如果一个对象可以被实例化为一个对象元素,则创建的对象 可以填写任何属性的属性元素形式 对象作为它们的基础类型。
您仍然可以提供对象值 对于不符合这些条件的类型,如果您启用一个值 转换器。有关详细信息,请参阅类型转换器和标记 XAML 的扩展。

从那里,您有两个选择:
1) 使用TypeConverter:
使用类型转换器将允许您在没有无参数构造函数的情况下实例化一个对象,但您必须提供一个可以执行实例化的 TypeConverter。

现在,我不必使用它,我无法进一步帮助您。

2) 使用 ServiceLocator 检索 IService:

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.
    }
}

我知道你的班级设计发生了变化,但希望你能应付它。

希望对你有帮助,

巴布。

【讨论】:

    【解决方案2】:

    如果您不希望 mef 创建您的用户控件,则必须在您的用户控件中使用 compositioncontainer 并直接调用 GetExport。但是你在获取你的 compositioncontainer 的实例时遇到了问题:)

    ps:我让 mef 在我的应用程序中创建我的 wpf 视图。

    【讨论】:

      【解决方案3】:

      (如果有人遇到它,我将恢复它。作为免责声明,我不是专家,这些只是我发现有效的解决方案。)

      我发现调用CompositionContainer.ComposeParts(myUserControl) 有效。我在控件的构造函数上调用它。您需要以某种方式获得对 CompositionContainer 的引用:

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

      其他解决方案:

      这可能是不必要的,但这是另一种方式。这要复杂得多,但它确实允许您在 XAML 中“Import”您的用户控件。

      为了满足您的导入,MyUserControl 需要导出,然后由 MEF 实例化。我的解决方案是在一个包含“定位器”对象的类中有静态字段。这个 Locator 对象负责导入和返回导出的对象。然后我可以在 XAML 中引用这个静态字段,如下所示:

      &lt;ContentControl Content="{Binding MyUserControl, Source={x:Static v:SomeClass.Locator}}"&gt;

      SomeClass 有一个名为Locator 的静态属性,它在应用程序生命周期的早期被分配。然后,定位器可以有一个 MyUserControl 属性,该属性获得 Imported。


      (免责声明:下面的链接是我自己的框架和解决方案,虽然很粗糙,如果使用应该小心使用。)

      为了提供上述示例,我将解释我是如何在我的框架中实现它的:

      在我的例子中,SomeClassSystem.Windows.Application 的子类,它替换了App.xaml,并且ViewLocator 被分配在它的OnStartup 上,可以看到here

      ViewLocator class 是一个 System.Dynamic.DynamicObject,用于导入具有自定义 ViewExport 属性的视图。使用ViewExportAttribute.Alias 属性标识视图。

      This 是导出视图并分配别名的示例。

      最后,可以在 XAML 中使用 MEF 实例化的视图实例,如下所示:

      &lt;ContentControl Content="{Binding HomeView, Source={x:Static v:FrameworkApp.ViewLocator}}"&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        相关资源
        最近更新 更多