Wpf 如何在我的Prism应用程序(如MS Office)中执行多个shell?
我尝试创建一个具有MS Office窗口行为的应用程序,例如Word/Excel。用户打开应用程序,单击“新建”时,将出现一个全新的窗口,显示应用程序的外观 到目前为止,我发现的最接近的是: 但是,这里的shell显示在应用程序启动时。如何通过命令做到这一点,或者可能有一种完全不同的方法来实现这一点 编辑:Wpf 如何在我的Prism应用程序(如MS Office)中执行多个shell?,wpf,mvvm,prism,Wpf,Mvvm,Prism,我尝试创建一个具有MS Office窗口行为的应用程序,例如Word/Excel。用户打开应用程序,单击“新建”时,将出现一个全新的窗口,显示应用程序的外观 到目前为止,我发现的最接近的是: 但是,这里的shell显示在应用程序启动时。如何通过命令做到这一点,或者可能有一种完全不同的方法来实现这一点 编辑: 我现在还发现了以下内容:,但是在哪里以及如何调用此代码?创建多个shell是正确的想法。你只需要适当地注意细节 何时以及如何创建新的Shell 当然,Prism的方法是使用DelegateC
我现在还发现了以下内容:,但是在哪里以及如何调用此代码?创建多个shell是正确的想法。你只需要适当地注意细节 何时以及如何创建新的Shell 当然,Prism的方法是使用
DelegateCommand
处理新shell的创建。考虑到这个命令并不严格属于任何特定的ViewModel(我想说它有一个应用程序范围),我觉得最好有一个public static类ApplicationWideCommands
和CreateNewShellCommand
静态属性。然后,您可以使用{x:Static}
从XAML绑定到它,或者根据需要从代码隐藏执行它
此命令需要处理两件事:
窗口
(实际上是一个外壳
)IRegionManager
,以便现有shell中的区域与新shell中的区域之间在区域名称上没有冲突IRegionManager
RegionManager
,因为区域名称在单个区域管理器的范围内必须是唯一的。由于区域名称是在视图的XAML中硬编码的,并且以另一种方式分配它们将是一件非常痛苦的事情,因此我们需要更改等式的另一半:每个shell使用的区域管理器实例。所以在Shell.xaml
中可能有如下内容:
<ContentControl
regions:RegionManager.RegionManager="{Binding RegionManager}"
regions:RegionManager.RegionName="ExampleRegion"
/>
<ItemsControl
regions:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Shell}}}"
regions:RegionManager.RegionName="AnotherRegion"
/>
所以现在我们只需要确保每个Shell
实例都有自己的RegionManager
。对于“第一个”shell,这将由引导程序执行。(下面的代码使用DI容器解析对象,示例使用UnityContainer
。如果使用MEF进行依赖项注入,只需在心里转换为等效代码即可。)
这里有一个重要的警告:RegionManager
作为单例注册到容器中。这意味着,无论何时解析IRegionManager
,都将返回相同的实例。因此,我们通过调用该方法创建一个新实例(这适用于Prism v4;我不确定v2)
此时,您知道如何创建任意数量的新Shell
实例并相应地连接区域
UI组合详细信息
您需要注意的最后一个细节是,每个shell中承载的所有区域,无论在其可视化树中有多深,都必须绑定到同一个RegionManager
这意味着您必须显式地设置区域管理器,以便像我们在上面的ContentControl
示例中那样,对应用程序中所有视图中的所有区域使用。幸运的是,这很容易做到,因为:
Shell
的后代Shell
已经将正确的RegionManager
作为属性公开,因此我们可以绑定到该属性<ContentControl
regions:RegionManager.RegionManager="{Binding RegionManager}"
regions:RegionManager.RegionName="ExampleRegion"
/>
<ItemsControl
regions:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Shell}}}"
regions:RegionManager.RegionName="AnotherRegion"
/>
准备就绪!
您现在应该可以开始了。这里是我现在用来创建具有多个EventAggregator的多个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);
}
}
公共静态类AppCommands
{
公共静态容器;
publicstaticicommand NewCommand=newdelegatecommand(CreateShell);
私有静态void CreateShell(对象状态)
{
var regionManager=Container.Resolve();
var newRegionManager=regionManager.CreateRegionManager();
var neweventAggregator=neweventAggregator();
容器.RegisterInstance(neweventAggregator);
var shell=新shell(newRegionManager、neweventAggregator);
shell.Show();
SomeEventParameter=新的SomeEventParameter();
//在此参数中添加某物
neweventAggregator.GetEvent().Publish(参数);
}
}
谢谢,这是一个很大的帮助,我的实现如下此答案中有一些事实上的错误。。。“UI组合详细信息”部分是不必要的。将区域名称指定给控件时,将自动创建区域。创建的区域将自动添加到逻辑树上距离该区域最近的区域管理器中。这就是作用域管理器的工作方式。因此,您需要做的就是确保新的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);
}
}