到目前为止我发现的最接近的是:Link
但是,这里的shell在应用程序启动时显示.如何通过命令来做到这一点,或者是否有完全不同的方式来实现呢?
何时以及如何创建新的Shell
当然,Prism的方式是让DelegateCommand处理创建一个新的shell.考虑到这个命令并不完全属于任何特定的viewmodel(我认为它有一个应用程序范围),对于一个具有CreateNewShellCommand静态属性的公共静态类ApplicationWideCommands,感觉更好.然后,您可以使用{x:Static}从XAML绑定,也可以根据需要从代码隐藏执行.
这个命令需要照顾两件事情:
>创建新窗口(实际上是一个Shell)
>为新的shell实例化一个新的IRegionManager,以便现有shell中的区域与新shell中的区域之间的区域名称没有冲突
>指示新shell中属于新IRegionManager的区域
我会处理这个最后一个,因为它更容易解释.
给你的新Shell一个新的RegionManager
在Prism中声明一个区域时,除了区域名称之外,您还可以声明使用区域管理器.通常,您不需要这样做,但是在这里,我们需要选择要使用哪个RegionManager,因为区域名称在单个区域管理器的范围内必须是唯一的.由于区域名称在视图的XAML内被硬编码,并且以另一种方式分配它们将是一个很大的痛苦,我们需要改变方程的另一半:每个shell使用的区域管理器实例.所以在Shell.xaml里面可能会有这样的东西:
<ContentControl regions:RegionManager.RegionManager="{Binding RegionManager}" regions:RegionManager.RegionName="ExampleRegion" />
这将指示它属于由绑定提供的IRegionManager的每个shell中的“WorkspaceRegion”.由于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.
这意味着您必须明确地将区域管理器设置为使用,就像我们在上述ContentControl示例中对应用程序中所有视图中的所有区域进行的操作一样.幸运的是,这很容易,因为:
>所有视图都将成为视觉树中Shell的后代
> Shell已经暴露了正确的RegionManager作为属性,因此我们可以绑定到该属性
你会这样做:
<ItemsControl regions:RegionManager.RegionManager="{Binding RegionManager,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Shell}}}" regions:RegionManager.RegionName="AnotherRegion" />
可以了,好了!
你现在应该准备好了.