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

时间:2011-03-11 18:41:24

标签: wpf mvvm prism

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

我到目前为止最接近的是:Link

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

编辑: 我现在也找到了以下内容:Link,但是在何处以及如何调用此代码?

2 个答案:

答案 0 :(得分:33)

创建多个shell是正确的想法。你只需要妥善处理细节。

何时以及如何创建新的Shell

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

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

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

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

    为您的新Shell提供新的RegionManager

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

    <ContentControl
      regions:RegionManager.RegionManager="{Binding RegionManager}"
      regions:RegionManager.RegionName="ExampleRegion"
    />
    

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

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

    现在我们只需要确保每个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);
    }
    

    对于其他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();
    }
    

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

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

    UI组成细节

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

    这意味着您必须显式设置区域管理器,就像我们在上面的ContentControl示例中为应用程序中所有视图中的所有区域所做的那样。幸运的是,这很容易做到,因为:

    1. 所有视图最终都将成为可视树中Shell的后代
    2. Shell已经将正确的RegionManager公开为属性,因此我们可以绑定到
    3. 你会这样做:

      <ItemsControl
        regions:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Shell}}}"
        regions:RegionManager.RegionName="AnotherRegion"
      />
      

      全部设定!

      你现在应该准备好了。

答案 1 :(得分:0)

这里是我现在用来创建多个带有多个EventAggregators的Shell的实现。我在引导程序中传递容器。在我的特殊情况下,子模块侦听事件以获取此Shell操作的路径参数。然后,子模块可以在路径位置创建节点数据文件,或者根据参数详细信息从路径位置加载。

public static class AppCommands
    {
        public static Container;

        public static ICommand NewCommand = new DelegateCommand(CreateShell);

        private static void CreateShell(object state)
        {
            var regionManager = Container.Resolve<IRegionManager>();
            var newRegionManager = regionManager.CreateRegionManager();
            var neweventAggregator = new EventAggregator();
            Container.RegisterInstance<EventAggregator>(neweventAggregator);
            var shell = new Shell(newRegionManager, neweventAggregator);

            shell.Show();
            SomeEventParameter parameter = new SomeEventParameter ();
            //Add sth to the parameter here

            neweventAggregator .GetEvent<SomeEvent>().Publish(parameter);
        }
    }