WPF/Prism:从两个不同的视图访问同一个VM实例



我目前正在进行我的第一个Prism项目,遇到了以下问题:

我的项目由两个区域组成,一个ContentRegion和一个MenuRegion,每个区域都应该访问ViewModel的同一实例。

在MenuRegion中,活动ViewModel的某些方法应该是可选的。在下面的示例中,Save方法应该能够从ContentRegion和MenuRegion中激发。

问题是,我最初创建了两个不同的ContentAViewModel实例,菜单的Save方法无法访问我的ContentRegion的当前数据。

我试过将ViewModels注册为singleton,但不幸的是,这不起作用,可能违反了Prism原则。

public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{

}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<ModuleA>();
}
}
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
public MainWindowViewModel(IContainerExtension container, IRegionManager regionManager)
{
_regionManager = regionManager;
_regionManager.RequestNavigate("ContentArea", "ContentAView");
_regionManager.RequestNavigate("MenuArea", "MenuA");
}
}
<Window
x:Class="PrismProject.Views.MainWindow"
xmlns:prism="http://prismlibrary.com/"
AllowsTransparency="True"
Background="Transparent"
xmlns:core="clr-namespace:PrismProject.Core;assembly=PrismProject.Core"
ResizeMode="CanResizeWithGrip"
WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--[...]-->
<ContentControl
Grid.Column="1"
Panel.ZIndex="10"
prism:RegionManager.RegionName="{x:Static core:RegionNames.MenuRegion}" />
<!--[...]-->
</Grid>

<ContentControl
Grid.Row="1"
prism:RegionManager.RegionName="{x:Static core:RegionNames.ContentRegion}" />
</Window>
public class ModuleA : IModule
{
private readonly IRegionManager _regionManager;
public CalculatingModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void OnInitialized(IContainerProvider containerProvider)
{
_regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(ContentAView));
_regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(ContentBView));
_regionManager.RegisterViewWithRegion(RegionNames.MenuRegion, typeof(MenuA));
_regionManager.RegisterViewWithRegion(RegionNames.MenuRegion, typeof(MenuB));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
//containerRegistry.RegisterSingleton<ContentAViewModel>();
//containerRegistry.RegisterSingleton<ContentBViewModel>();
ViewModelLocationProvider.Register<MenuA, ContentAViewModel>();
ViewModelLocationProvider.Register<MenuB, ContentBViewModel>();
}
}
public class ContentAViewModel: RegionViewModelBase
{
private readonly IRegionManager _regionManager;
public ContentAViewModel(IRegionManager regionManager) : base(regionManager)
{
SaveCommand = new(Save);
_regionManager = regionManager;
}

private void Save()
{
// logic
}
}
<UserControl
x:Class="PrismProject.Modules.ModuleA.Views.ContentAView"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Button 
Command="{Binding SaveCommand}"
Content="Save"/>
<!--[...]-->
</Grid>
</UserControl>
<UserControl
x:Class="PrismProject.Modules.ModuleA.Menus.MenuA"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Menu>                
<MenuItem
Command="{Binding SaveCommand}"
Header="Save"/>
<!--[...]-->
</Menu>
</Grid>
</UserControl>

如何在只使用ViewModel的一个实例时将同一个ViewModel分配给多个视图?

我必须做同样的事情。我在他的一个在线视频中使用了布莱恩·拉古纳斯(《棱镜》的作者之一(提出的一种优雅的技巧。是来自一个优秀的教程网站,我不会命名,以免听起来像一个骗子,但如果你谷歌"棱镜问题&解决方案:加载依赖视图";你会发现的。我强烈建议你看。但我会在这里给你介绍一下技巧。

(在我的情况下,我的模块的每个主视图都需要与Prism需要自动放入我定义的另一个区域的"工具"视图共享其视图模型(

  1. 创建一个属性(我称之为PageToolAttribute(,该属性采用";"伴侣";视图
  2. 将该属性应用于您的";主";应该与配套视图共享其视图模型的视图。供应名称为";要显示在其他"棱镜"区域中的配套视图
  3. 创建一个从Prism的RegionBehavior类派生的类,该类(在其对OnAttach的覆盖中(挂接到Prism Region的ActiveViews.CollectionChanged事件。在处理程序中,您会询问新添加的视图是否具有PageToolAttribute
  4. 如果新添加的视图确实支持该属性,那么您的事件处理程序将获取其名称并创建其新实例,为其提供与视图相同的DataContext(即,您想要共享的视图模型(,并最终将其他区域导航到新添加的图观
  5. 最后,在Prism Aap中,覆盖ConfigureDefaultRegionBehaviors函数并调用AddIfMissing(在提供的IRegionBehaviorFactory上(来添加属性

这是一项艰巨的任务,需要深入研究Prism,但代码量惊人地少,而且它的工作方式就像冠军一样。我现在有7个不同的模块,每个模块都有自己的配套"模块";工具";每次导航的视图。

最新更新