【问题标题】:ViewModel instatiated twice with MEFViewModel 使用 MEF 实例化了两次
【发布时间】:2015-09-28 15:28:31
【问题描述】:

我正在尝试使用 MEF 创建一个简单的模块化 MVVM 应用程序。我有一个 ViewModel 类和一个 UserControl 作为视图。我通过 DataTemplate 将两者连接起来,如下所示:

<DataTemplate DataType="{x:Type local:MyViewModel}">
    <local:MyView />
</DataTemplate>

在 View 中,我将 ViewModel 定义为 StaticResource,以简化绑定:

<UserControl.Resources>
    <local:MyViewModel x:Key="ViewModel" />
</UserControl.Resources>

然后我这样绑定:

<Grid DataContext="{StaticResource ResourceKey=ViewModel}">
    <TextBlock Text="{Binding Text}" />
</Grid>

这一切都可以在没有 MEF 的情况下按预期工作。但是,由于我的目标是模块化,因此我使用 MEF 来发现我的 ViewModel 类。我的 ViewModel 类上有一个 Export 属性:

[Export(typeof(MyViewModel))]
public class MyViewModel
{
    // ...
}

我使用 MEF 将 ViewModel 动态加载到 App.xaml.cs 中的 shell:

private void Application_Startup(object sender, StartupEventArgs e)
{
    var shell = new MainWindow();
    var catalog = new AssemblyCatalog(this.GetType().Assembly);
    var container = new CompositionContainer(catalog);

    shell.Contents.ViewModel = container.GetExportedValues<MyViewModel>().First();

    shell.Show();
}

现在,此时,MEF 在加载 vm 时创建了我的 ViewModel 的一个实例,而我的 View 在将 vm 声明为资源时创建了另一个实例。 (这很容易通过在构造函数中设置断点来检查。)

问题是,我应该如何将 MEF 创建的实例传递给我的资源声明?我可以将该特定实例声明为资源吗?

带有完整代码的 DropBox 链接: https://www.dropbox.com/sh/pbdl029d26sx7gl/AAA6po50dLjbJSoNPBhCyWZ3a?dl=0

【问题讨论】:

  • 根据这个答案使用 DataContextSpy 修改了我的基础架构:stackoverflow.com/a/5402653/5219911 让这个问题稍微开放一下,以防有人提出另一个想法,但这似乎目前可行。

标签: c# wpf xaml mvvm mef


【解决方案1】:

MyViewModel 的创建完全基于程序执行的顺序,但您可以设置 CreationPolicy 以使您的实例成为单例,以便您的代码和资源都引用同一个实例。

[Export(typeof(MyViewModel)), PartCreationPolicy(CreationPolicy.Shared)]

旁注:为了使用 MEF,Microsoft 出于某种原因从 .Net 框架中隐藏了 CompositionInitializer 和 CompositionHost 的实现。尝试 google 并从 Microsoft 导入 2 个类,而不是直接使用 CompositionContainer。您将在使用 MEF 时获得更好的体验。

【讨论】:

  • 不幸的是,这仅告诉 MEF 仅实例化我的视图模型一次。问题是 MEF 和 WPF 资源查找都试图实例化所述视图模型。如果我直接创建视图,我将能够添加视图模型资源。但是,由于视图是从 DataTemplate 创建的,因此我没有对视图的引用来直接访问其资源。
【解决方案2】:

好的,所以,我要做的就是这个。

我有两个实例,因为一次 MEF 在导入 ViewModel 时实例化它们,然后 WPF 在创建 ViewModel 资源时创建它们。我认为解决方案不会直接创建资源,但不知道我该如何做到这一点。然后是资源注入,然后是 DataContextSpy,来自这个问题: https://stackoverflow.com/a/5402653/5219911

这里是该主题的直接链接: http://www.codeproject.com/Articles/27432/Artificial-Inheritance-Contexts-in-WPF

我现在使用的资源是 DataContextSpy,通过它我可以访问创建 DataTemplate 时使用的 ViewModel 实例。

在我的视图资源中,我定义 然后我只是将根元素的 DataContext 设置为此资源: DataContext="{绑定源={StaticResource ResourceKey=ViewModel}, 路径=DataContext}"

现在,不幸的是,我并没有单独获得 Intellisense 支持,因为 DataContextSpy 是真实 DataContext 的代理,所以我必须手动设置设计时 DataContext 类型,方法是: d:DataContext="{d:DesignInstance Type=viewModel:MyViewModel}"

【讨论】:

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