如何在我的Prism应用程序(如MS Office)中执行多个shell?

ps2*_*s23 19 wpf prism mvvm

我尝试创建一个具有MS Office窗口行为的应用程序,例如Word/Excel.用户打开应用程序,单击新建时,将出现一个全新的窗口,其中包含应用程序的外观.

到目前为止我发现的最接近的是:链接

但是,这里的shell在应用程序启动时显示.如何通过命令执行此操作,或者可能有完全不同的方法来实现此目的?

编辑:我现在也发现了以下内容:链接,但在哪里以及如何调用此代码?

Jon*_*Jon 33

创建多个shell是正确的想法.您只需要适当地处理细节.

何时以及如何创建新的Shell

当然,Prism的方法是DelegateCommand处理新shell的创建.考虑到这个命令并不严格属于任何特定的ViewModel(我说它有一个应用程序范围),对于我来说,拥有public static class ApplicationWideCommands一个CreateNewShellCommand静态属性感觉更好.然后,您可以根据需要从XAML绑定到它{x:Static}或从代码隐藏执行它.

这个命令需要处理两件事:

  1. 创建新的Window(实际上,a Shell)
  2. IRegionManager为新shell 实例化一个新的,以便现有shell中的区域与新shell中的区域之间的区域名称不会发生冲突
  3. 指示新shell中属于新区域的区域 IRegionManager

我将从头到尾解决这个问题,因为它更容易解释.

为您的新Shell提供一个新的RegionManager

在Prism中声明区域时,除了区域名称之外,您还可以声明要使用的区域管理器.通常您不需要这样做,但在这里我们需要选择RegionManager使用哪个,因为区域名称在单个区域管理器的范围内必须是唯一的.由于区域名称在视图的XAML中是硬编码的,并且以另一种方式分配它们将是一个主要的痛苦,我们需要更改方程的另一半:每个shell使用的区域管理器实例.所以里面Shell.xaml可能会有这样的事情:

<ContentControl
  regions:RegionManager.RegionManager="{Binding RegionManager}"
  regions:RegionManager.RegionName="ExampleRegion"
/>
Run Code Online (Sandbox Code Playgroud)

这将指示它属于IRegionManager绑定提供的每个shell中的"WorkspaceRegion" .由于shell通常没有DataContext,我们可以RegionManager在shell类本身声明属性:

public partial class Shell : Window
{
    public Shell(IRegionManager regionManager)
    {
        this.RegionManager = regionManager;
        InitializeComponent();
    }

    public IRegionManager RegionManager { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

所以现在我们只需要确保每个Shell实例都有自己的实例RegionManager.对于"第一个"shell,这将由BootStrapper.(下面的代码使用DI容器来解析对象,并且示例使用UnityContainer.如果使用MEF进行依赖注入,只需在心理上转换为等效代码.)

protected override DependencyObject CreateShell()
{
    // I am assuming you have a reference to the DI container
    var regionManager = this.Container.Resolve<IRegionManager>();
    return new Shell(regionManager);
}
Run Code Online (Sandbox Code Playgroud)

对于其他shell,它将通过以下方式完成CreateNewShellCommand:

private static ExecuteCreateNewShellCommand()
{
    // I am assuming you have a reference to the DI container
   var regionManager = this.Container.Resolve<IRegionManager>();
   ver newRegionManager = regionManager.CreateRegionManager();
   var shell = new Shell(newRegionManager);

   // The rest is easy, for example:
   shell.Show();
}
Run Code Online (Sandbox Code Playgroud)

这里有一个重要的警告:RegionManager作为单身人士注册到容器中.这意味着无论何时解决,IRegionManager 您都将获得相同的实例.出于这个原因,我们通过调用IRegionManager.CreateRegionManager方法创建一个新实例(这适用于Prism v4;我不确定v2).

此时,您知道如何创建任意数量的新Shell实例并相应地连接区域.

UI组合细节

您需要注意的最后一个细节是,每个shell中托管的所有区域,无论其可视树有多深,都必须绑定到相同的区域RegionManager.

这意味着您必须像ContentControl上面的示例中那样显式设置区域管理器,以用于应用程序中所有视图中的所有区域.幸运的是,这很容易完成,因为:

  1. 所有视图最终都将成为Shell可视树中a的后代
  2. Shell已经公开正确RegionManager的属性,所以我们可以绑定到

你会这样做:

<ItemsControl
  regions:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Shell}}}"
  regions:RegionManager.RegionName="AnotherRegion"
/>
Run Code Online (Sandbox Code Playgroud)

搞定!

你现在应该准备好了.

  • 这个答案中有一些事实上的不准确之处......"UI组合细节"这一部分是不必要的.将区域名称分配给控件时,将自动创建一个区域.创建的区域将自动添加到最靠近逻辑树上区域的区域管理器中.这就是范围内的区域经理的工作方式.所以你需要做的就是确保你的新shell实例有自己的区域管理器.或者在每个shell中创建一个唯一命名的区域,并使用作用域区域管理器实例.无论哪个漂浮你的船. (2认同)