WPF/Prism:从两个不同的视图访问同一个虚拟机实例
WPF/Prism: Access to the same VM-instance from two different views
我目前正在处理我的第一个 Prism 项目,但遇到了以下问题:
我的项目由两个区域组成,一个 ContentRegion 和一个 MenuRegion,每个区域都应该访问相同的 ViewModel 实例。
在 MenuRegion 中,活动 ViewModel 的一些方法应该是可选的。
在下面的示例中,应该能够从 ContentRegion 和 MenuRegion 中触发 Save 方法。
问题是我最初创建了两个不同的 ContentAViewModel 实例,菜单的 Save 方法无法访问我的 ContentRegion 的当前数据。
我试过将 ViewModels 注册为单例,但不幸的是这不起作用并且可能违反了 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 分配给多个视图?
我必须做同样的事情。我使用了 Brian Lagunas(Prism 的作者之一)在他的一个在线视频中展示的一种优雅的技术。来自一个优秀的教程网站,我不会命名以免听起来像托儿,但如果您 google“Prism 问题和解决方案:加载相关视图”,您会找到它。我强烈推荐观看它。但是我会在这里给你概述这个技术。
(在我的例子中,我模块的每个主要视图都需要与 Prism 需要自动放入我定义的另一个区域的“工具”视图共享其视图模型)
- 创建一个属性(我称之为
PageToolAttribute
)以“伴随”视图的名称命名
- 将属性应用于您的“主”视图,该视图应与伴随视图共享其 view-model。提供您希望在其他 Prism 区域中显示的“伴随视图”的名称。
- 创建一个派生自 Prism 的
RegionBehavior
class 的 class,它(在其对 OnAttach
的覆盖中)挂钩到 Prism 区域的 ActiveViews.CollectionChanged
事件。在处理程序中,您询问新添加的视图是否具有 PageToolAttribute
.
- 如果新添加的视图 支持该属性,您的事件处理程序将获取它的名称并创建它的新实例,并赋予它与
DataContext
相同的属性视图(即您要共享的 view-model),最后将其他区域导航到新添加的视图。
- 最后,在您的 Prism Aap 中,您覆盖
ConfigureDefaultRegionBehaviors
函数并调用 AddIfMissing
(在提供的 IRegionBehaviorFactory
上)以添加您的属性。
要接受的内容很多,需要对 Prism 进行一些深入的研究,但代码量却出乎意料地少,而且它的工作原理非常出色。我现在有 7 个不同的模块,每个模块都有自己的配套“工具”视图,每次都会导航。
我目前正在处理我的第一个 Prism 项目,但遇到了以下问题:
我的项目由两个区域组成,一个 ContentRegion 和一个 MenuRegion,每个区域都应该访问相同的 ViewModel 实例。
在 MenuRegion 中,活动 ViewModel 的一些方法应该是可选的。 在下面的示例中,应该能够从 ContentRegion 和 MenuRegion 中触发 Save 方法。
问题是我最初创建了两个不同的 ContentAViewModel 实例,菜单的 Save 方法无法访问我的 ContentRegion 的当前数据。
我试过将 ViewModels 注册为单例,但不幸的是这不起作用并且可能违反了 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 分配给多个视图?
我必须做同样的事情。我使用了 Brian Lagunas(Prism 的作者之一)在他的一个在线视频中展示的一种优雅的技术。来自一个优秀的教程网站,我不会命名以免听起来像托儿,但如果您 google“Prism 问题和解决方案:加载相关视图”,您会找到它。我强烈推荐观看它。但是我会在这里给你概述这个技术。
(在我的例子中,我模块的每个主要视图都需要与 Prism 需要自动放入我定义的另一个区域的“工具”视图共享其视图模型)
- 创建一个属性(我称之为
PageToolAttribute
)以“伴随”视图的名称命名 - 将属性应用于您的“主”视图,该视图应与伴随视图共享其 view-model。提供您希望在其他 Prism 区域中显示的“伴随视图”的名称。
- 创建一个派生自 Prism 的
RegionBehavior
class 的 class,它(在其对OnAttach
的覆盖中)挂钩到 Prism 区域的ActiveViews.CollectionChanged
事件。在处理程序中,您询问新添加的视图是否具有PageToolAttribute
. - 如果新添加的视图 支持该属性,您的事件处理程序将获取它的名称并创建它的新实例,并赋予它与
DataContext
相同的属性视图(即您要共享的 view-model),最后将其他区域导航到新添加的视图。 - 最后,在您的 Prism Aap 中,您覆盖
ConfigureDefaultRegionBehaviors
函数并调用AddIfMissing
(在提供的IRegionBehaviorFactory
上)以添加您的属性。
要接受的内容很多,需要对 Prism 进行一些深入的研究,但代码量却出乎意料地少,而且它的工作原理非常出色。我现在有 7 个不同的模块,每个模块都有自己的配套“工具”视图,每次都会导航。