WPF,MEF,Prism - 如何在shell中设置DataContext

时间:2015-01-21 10:27:15

标签: wpf mvvm prism mef prism-4

我正在使用WPF / PRISM / MEF作为桌面应用程序。

这是一个包含三个区域的简单测试应用程序。视图定义于 外部模块。

看来我需要设置我的shell DataContext。所以我把它设置为视图模型 如下图所示 - 应用程序行为正常。

我对制作明确的定义不满意。是不可能的 在初始化期间,加载一些模块,并找到一些视图并将其分配给 我的shell的DataContext?我在哪里可以找到文档 - 我一定错过了它 在开发人员指南(以及示例应用程序)中。或者,有人有建议吗?

Shell.xaml:

<Window x:Class="TestMenuTaskbarDT.Shell"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:prism="http://www.codeplex.com/prism"   

  xmlns:local_viewmodels="clr-namespace:TestMenuTaskbarModuleMain.ViewModels;assembly=TestMenuTaskbarModuleMain"
    . . .
>

  <Window.InputBindings>
    <KeyBinding Key="S" Modifiers="Control" Command="{Binding Path=CloseProjectCommand}" />
    <KeyBinding Key="O" Modifiers="Control" Command="{Binding Path=OpenProjectCommand}" />
  </Window.InputBindings>
  <StackPanel>
    <ItemsControl Name="MainMenuRegion" prism:RegionManager.RegionName="MainMenuRegion" />
    <ItemsControl Name="MainToolbarRegion" prism:RegionManager.RegionName="MainToolbarRegion" />
    <ItemsControl Name="MainContentRegion" prism:RegionManager.RegionName="MainContentRegion" />
  </StackPanel>
  <!-- How does one set the datacontext, when it should be dynamically loaded? -->
  <Window.DataContext>
    <local_viewmodels:MainWindowViewModel />
  </Window.DataContext>

</Window>

(或者应该将local_viewmodels ...放入资源并以某种方式设置在那里?)

然后我可以在Bootstrapper中添加如下内容吗?或者是否有完全不同的技术?

Bootstrapper.cs:

. . .
class Bootstrapper : MefBootstrapper
{
    . . .
  protected override IModuleCatalog CreateModuleCatalog()
  {
      // All dlls are expected to reside in the same directory as the *.exe
      return new DirectoryModuleCatalog() { ModulePath = System.AppDomain.CurrentDomain.BaseDirectory };           
  }

  protected override void ConfigureAggregateCatalog()
  {
      base.ConfigureAggregateCatalog();
      this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
      // Module registration remains the same *IT* registers the views with the region catalog
      this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(TestMenuTaskbarModuleMain.TestMenuTaskbarModuleMain).Assembly));
  }
    . . .

  protected override void InitializeShell()
  {
    base.InitializeShell();
    Application.Current.MainWindow = (Window)this.Shell;
    // Is something like the following possible?
      _MyBaseViewModel = GetAViewModelSomehowFromAModule("MyViewModelKey");
      Application.Current.MainWindow.DataContext = _MyBaseViewModel;
    //
    Application.Current.MainWindow.Show();                 // Displays MainWindow

    }

2 个答案:

答案 0 :(得分:1)

在我的Shell.xaml.cs中,我定义了这个属性:

[Import]
ShellViewModel ViewModel
{
    set
    {
        this.DataContext = value;
    }
}

然后在我的ShellViewModel类中,构造函数将像这样装饰......

[Export]
public class ShellViewModel

因此依靠MEF组合导入/导出属性来实现DataContext设置。这是一个简化的示例,但您可能希望进一步研究组合插入性错误等问题。

答案 1 :(得分:0)

如果我理解Dynamoid,我应该使用以下内容:

namespace TestMenuTaskbarDT
{     
  [Export]
  public partial class Shell : Window
  {
    [ImportingConstructor] public Shell([Import("ShellViewModel")]object aShellViewModel)
    {
        InitializeComponent();
        //NOTE: DataContext is magically set from the imported object "aShellViewModel."
        // I assume MEF uses Reflection to magically resolve all internal references.
        DataContext = aShellViewModel;
    }

    /* removed, ImportingConstructor does it all in one step.
    Note: DataContext is magically set from "value."
    [Import("ShellViewModel")]
    public object ViewModel
    {
        set { this.DataContext = value; }
    }
     */
}

}

显然,初始化的一步构造比第一个构造的两步形式然后初始化更简单。 (所以人们应该点击dynamoids评论给他他应得的 - 不仅仅是因为他的暗示,而且还因为他坚持不懈地指出他的观点。)

(这里唯一留下的就是让它在设计时正确显示 - 但这是一个不同的混乱。)