C# ViewModel使用MEF安装了两次

C# ViewModel使用MEF安装了两次,c#,wpf,xaml,mvvm,mef,C#,Wpf,Xaml,Mvvm,Mef,我试图用MEF创建一个简单的模块化MVVM应用程序。我有一个ViewModel类和一个UserControl作为视图。我通过DataTemplate将两者连接起来,如下所示: <DataTemplate DataType="{x:Type local:MyViewModel}"> <local:MyView /> </DataTemplate> <Grid DataContext="{StaticResource ResourceKey=Vie

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

<DataTemplate DataType="{x:Type local:MyViewModel}">
    <local:MyView />
</DataTemplate>
<Grid DataContext="{StaticResource ResourceKey=ViewModel}">
    <TextBlock Text="{Binding Text}" />
</Grid>
我使用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();
}
private void应用程序\u启动(对象发送方,StartupEventArgs e)
{
var shell=新的主窗口();
var catalog=newassemblycalog(this.GetType().Assembly);
var容器=新的合成容器(目录);
shell.Contents.ViewModel=container.GetExportedValues().First();
shell.Show();
}
现在,MEF在加载vm时创建了我的ViewModel的一个实例,而我的视图在将vm声明为资源时创建了另一个实例。(这可以通过在构造函数中设置断点轻松检查。)

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

具有完整代码的DropBox链接:

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

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


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

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

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


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

好的,所以,我要做的就是这样

我有两个实例,因为一次MEF在导入ViewModel时实例化了它们,另一次WPF在创建ViewModel资源时创建了它们。我认为解决方案不会直接创建资源,但不知道如何才能做到这一点。然后是资源注入,然后是DataContextSpy,从这个问题:

以下是与主题的直接链接:

我现在使用的资源是DataContextSpy,通过它我可以接触到创建DataTemplate时使用的ViewModel实例

在我的视图资源中,我定义 然后我将根元素的DataContext设置为这个资源: DataContext=“{Binding Source={StaticResourceKey=ViewModel}, 路径=数据上下文}”

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

好的,我要做的就是这样

我有两个实例,因为一次MEF在导入ViewModel时实例化了它们,另一次WPF在创建ViewModel资源时创建了它们。我认为解决方案不会直接创建资源,但不知道如何才能做到这一点。然后是资源注入,然后是DataContextSpy,从这个问题:

以下是与主题的直接链接:

我现在使用的资源是DataContextSpy,通过它我可以接触到创建DataTemplate时使用的ViewModel实例

在我的视图资源中,我定义 然后我将根元素的DataContext设置为这个资源: DataContext=“{Binding Source={StaticResourceKey=ViewModel}, 路径=数据上下文}”

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

不幸的是,这只告诉MEF仅实例化一次我的viewModel。问题是MEF和WPF资源查找都试图实例化所述viewModel。如果直接创建视图,则可以添加viewmodel资源。但是,由于视图是从DataTemplate创建的,因此我没有对视图的引用来直接访问其资源。不幸的是,这只告诉MEF仅实例化一次我的viewmodel。问题是MEF和WPF资源查找都试图实例化所述viewmodel。如果直接创建视图,则可以添加viewmodel资源。但是,由于该视图是从DataTemplate创建的,因此我没有对该视图的引用来直接访问其资源。使用DataContextSpy修改了我的基础结构,这是基于以下回答的:将问题保留一段时间,以防有人提出另一个解决方案,但这在目前看来是可行的。使用DataContextSpy修改了我的基础设施,基于以下答案:将问题留待一段时间,以防有人提出另一个解决方案,但这在目前看来是可行的。
[Export(typeof(MyViewModel))]
public class MyViewModel
{
    // ...
}
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();
}