ViewModel使用MEF实例化两次

时间:2015-09-28 15:28:32

标签: c# wpf xaml mvvm mef

我正在尝试使用MEF创建一个简单的模块化MVVM应用程序。我有一个ViewModel类和一个UserControl作为View。我通过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在App.xaml.cs中将ViewModel动态加载到我的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

2 个答案:

答案 0 :(得分:0)

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

[导出(typeof(MyViewModel)),PartCreationPolicy(CreationPolicy.Shared)]

附注:为了使用MEF,Microsoft出于某种原因隐藏了.Net Framework中的CompositionInitializer和CompositionHost的实现。尝试谷歌并从Microsoft导入2个类,而不是直接使用CompositionContainer。您在使用MEF方面有更好的经验。

答案 1 :(得分:0)

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

我有两个实例,因为一旦MEF在导入它们时实例化ViewModels,然后WPF在创建ViewModel资源时再创建它们。我认为解决方案不会直接创建资源,但不知道我怎么能设法做到这一点。接下来是资源注入,然后是DataContextSpy,来自这个问题: AGGREGATE function

以下是该主题的直接链接: https://stackoverflow.com/a/5402653/5219911

我现在正在使用一个DataContextSpy资源,通过它我可以联系到创建DataTemplate时使用的ViewModel实例。

在我的View资源中,我定义了      然后我只是将根元素的DataContext设置为此资源:     DataContext =“{Binding Source = {StaticResource ResourceKey = ViewModel},                                      路径= DataContext的}“

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