通过在 WPF Prism 中注入特定的 ViewModel 导航到视图
Navigate to View by injecting specific ViewModel in WPF Prism
我有一个特定于 WPF 和 Prism 的设计相关问题。我正在开发一个规则应用程序,我需要在 TreeView 控件中以分层方式显示不同类型的规则(模型)。我已将模型的每个实例包装在各自的 ViewModel 中,并将其绑定到 TreeView。下面我试图描述层次结构,只是为了强调可以有多个相同类型的 ViewModel,并且根据它们的选择,我需要相应地显示它们各自的视图。
规则
---组(GroupViewModel实例1)
------ X(XViewModel 实例 1)
------------ Z(ZViewModel实例1)
------ X(XViewModel 实例 2)
---组(GroupViewModel实例2)
------ Y(YViewModel 实例 1)
------ Z(ZViewModel实例2)
------------ X(XViewModel 实例 3)
问题:
我需要一种机制来首先从 TreeView 中获取选定的项目,然后使用基于树项目选择的 Uri(以实现松散耦合)导航到 ViewModel 的视图,并feed/inject 视图中选定的 ViewModel。
需要代码示例来获取选定的 ViewModel、导航到 View 以及注入 ViewModel?
目标:
我正在寻找一些最佳实践来使用 Prism 在 WPF 中处理这种情况以保持松耦合。
重要说明: TreeView 显示在一个区域中,内容是另一个区域的一部分,我正在使用 MEF DI 容器。
1) 假设 "Execute" 是某种业务逻辑,那么在模型 class 中使用它似乎是完全有效的。同上验证。事实上,这可能是给定的,因为您希望将所有业务逻辑和验证集中在一个地方。该模型可以(可能)在未来被重复使用,比如说,如果您决定在现有模型之上开发一个基于网络的系统。事实上我 once asked a similar question 前段时间给你的。
我个人认为 "rich" 模型 class 很好,包括实现 INotifyPropertyChanged
的属性,使其成为 "binding friendly"。这是完全可以接受的,因为此接口不存在于 UI 相关的框架命名空间 (System.ComponentModel) 中。为了方便起见,我什至在我的模型中包含了 ICommand 属性,尽管这取决于你是 "purist" 的程度,模糊了模型定义和视图模型之间的界限。这就引出了你的第二个问题——有了这样一个模型,它可以通过 VM 属性 暴露模型直接绑定到视图。
许多 WPF 开发人员似乎编写的 VM classes 基本上是模型 classes 的镜像(带有所有 to/from 映射代码) ,但包括 INPC 属性和 ICommands 之类的东西。这是我(个人)从未见过的很多开销。同样,关于您如何使用模型和 VM,似乎有两个 "camps",可能在某种程度上取决于您的应用程序需要如何 "tiered"。很多也归结为个人喜好,就像许多开发挑战一样,我认为没有正确或错误的方法。
关于 3),是否要单击 TreeView 中的项目,导致视图显示在应用程序的其他位置?我假设您正在使用依赖注入框架? AFAIK Prism 区域管理器需要这个,我不知道在没有 DI 框架的情况下使用区域管理器的方法。
您首先需要定义一个显示该视图的区域,例如:-
<ContentControl Regions:RegionManager.RegionName="MyRegionName" />
要在您使用 Prism 区域管理器的区域中显示视图:-
_regionManager.RequestNavigate("MyViewName", "MyRegionName");
视图名称是在您向 DI 框架注册视图时指定的,例如这是在温莎城堡中的做法:-
Container.Register(Component.For<MyView>().ImplementedBy<MyView>().LifeStyle.Transient.Named("MyViewName"));
希望这能让您顺利上路。 Prism 导航有很多功能,尤其是让您了解视图生命周期。此外,让正在导航的视图的 VM 实现 INavigationAware
通常很有用,这样它就可以对事件做出反应,例如正在导航 to/from.
编辑(基于OP编辑):
你还没有说区域是否与TreeView 在同一个视图中。如果是,那么您可能无需 Prism 导航即可实现此目的。 "main" VM(与 TreeView 的视图相关)可以公开当前选择的规则 VM(当然是作为 INotifyPropertyChanged 属性!),您可以将其绑定到 ContentControl:
<ContentControl Content="{Binding SelectedRule}" />
那么这只是为规则虚拟机设置 DataTemplates 的情况:-
<DataTemplate DateType="{x:Type XRuleViewModel}">
... XAML ...
</DataTemplate>
随着 TreeView 选择的变化,ContentControl 将绑定到适当的规则 VM,相应的 DataTemplate 将呈现所需的内容。
如果区域 是 在单独的视图中,那么您将需要使用 Prism 导航。这里的问题是您需要要导航到的视图的名称,但是您的 "main" (TreeView) VM 不了解视图,只有规则 VM。一个简单的选择可能是在您的规则 VM 上设置一个 属性 来公开相关的视图名称。如果您更像是一个纯粹主义者,并且希望将这些知识排除在 VM 之外,那么您可以实施一种机制,在该机制中,您可以使用相应视图的名称注册所有规则 VM(例如,在应用程序启动期间)。这可以像 Dictionary
一样简单。在 TreeView 中选择规则 VM 时,您只需查找相应的视图名称以在 RequestNavigate()
调用中使用。
@Andrew 走在正确的轨道上。首先,除非您的架构绝对需要,否则无需将您的模型包装在 ViewModel 中。我猜它不会。完成此任务的最简单方法是使用 InvokeCommandAction 响应所选项目更改事件。然后执行将导航到所需视图的命令。使用所选项目作为参数来确定您要查找的视图。导航时,您还可以使用 NavigationParameters 将所选项目作为参数传递,并在目标上使用 INavigationAware 以便在 OnNavigatedTo 方法中获取该参数。
我有一个特定于 WPF 和 Prism 的设计相关问题。我正在开发一个规则应用程序,我需要在 TreeView 控件中以分层方式显示不同类型的规则(模型)。我已将模型的每个实例包装在各自的 ViewModel 中,并将其绑定到 TreeView。下面我试图描述层次结构,只是为了强调可以有多个相同类型的 ViewModel,并且根据它们的选择,我需要相应地显示它们各自的视图。
规则
---组(GroupViewModel实例1)
------ X(XViewModel 实例 1)
------------ Z(ZViewModel实例1)
------ X(XViewModel 实例 2)
---组(GroupViewModel实例2)
------ Y(YViewModel 实例 1)
------ Z(ZViewModel实例2)
------------ X(XViewModel 实例 3)
问题:
我需要一种机制来首先从 TreeView 中获取选定的项目,然后使用基于树项目选择的 Uri(以实现松散耦合)导航到 ViewModel 的视图,并feed/inject 视图中选定的 ViewModel。 需要代码示例来获取选定的 ViewModel、导航到 View 以及注入 ViewModel?
目标:
我正在寻找一些最佳实践来使用 Prism 在 WPF 中处理这种情况以保持松耦合。
重要说明: TreeView 显示在一个区域中,内容是另一个区域的一部分,我正在使用 MEF DI 容器。
1) 假设 "Execute" 是某种业务逻辑,那么在模型 class 中使用它似乎是完全有效的。同上验证。事实上,这可能是给定的,因为您希望将所有业务逻辑和验证集中在一个地方。该模型可以(可能)在未来被重复使用,比如说,如果您决定在现有模型之上开发一个基于网络的系统。事实上我 once asked a similar question 前段时间给你的。
我个人认为 "rich" 模型 class 很好,包括实现 INotifyPropertyChanged
的属性,使其成为 "binding friendly"。这是完全可以接受的,因为此接口不存在于 UI 相关的框架命名空间 (System.ComponentModel) 中。为了方便起见,我什至在我的模型中包含了 ICommand 属性,尽管这取决于你是 "purist" 的程度,模糊了模型定义和视图模型之间的界限。这就引出了你的第二个问题——有了这样一个模型,它可以通过 VM 属性 暴露模型直接绑定到视图。
许多 WPF 开发人员似乎编写的 VM classes 基本上是模型 classes 的镜像(带有所有 to/from 映射代码) ,但包括 INPC 属性和 ICommands 之类的东西。这是我(个人)从未见过的很多开销。同样,关于您如何使用模型和 VM,似乎有两个 "camps",可能在某种程度上取决于您的应用程序需要如何 "tiered"。很多也归结为个人喜好,就像许多开发挑战一样,我认为没有正确或错误的方法。
关于 3),是否要单击 TreeView 中的项目,导致视图显示在应用程序的其他位置?我假设您正在使用依赖注入框架? AFAIK Prism 区域管理器需要这个,我不知道在没有 DI 框架的情况下使用区域管理器的方法。
您首先需要定义一个显示该视图的区域,例如:-
<ContentControl Regions:RegionManager.RegionName="MyRegionName" />
要在您使用 Prism 区域管理器的区域中显示视图:-
_regionManager.RequestNavigate("MyViewName", "MyRegionName");
视图名称是在您向 DI 框架注册视图时指定的,例如这是在温莎城堡中的做法:-
Container.Register(Component.For<MyView>().ImplementedBy<MyView>().LifeStyle.Transient.Named("MyViewName"));
希望这能让您顺利上路。 Prism 导航有很多功能,尤其是让您了解视图生命周期。此外,让正在导航的视图的 VM 实现 INavigationAware
通常很有用,这样它就可以对事件做出反应,例如正在导航 to/from.
编辑(基于OP编辑):
你还没有说区域是否与TreeView 在同一个视图中。如果是,那么您可能无需 Prism 导航即可实现此目的。 "main" VM(与 TreeView 的视图相关)可以公开当前选择的规则 VM(当然是作为 INotifyPropertyChanged 属性!),您可以将其绑定到 ContentControl:
<ContentControl Content="{Binding SelectedRule}" />
那么这只是为规则虚拟机设置 DataTemplates 的情况:-
<DataTemplate DateType="{x:Type XRuleViewModel}">
... XAML ...
</DataTemplate>
随着 TreeView 选择的变化,ContentControl 将绑定到适当的规则 VM,相应的 DataTemplate 将呈现所需的内容。
如果区域 是 在单独的视图中,那么您将需要使用 Prism 导航。这里的问题是您需要要导航到的视图的名称,但是您的 "main" (TreeView) VM 不了解视图,只有规则 VM。一个简单的选择可能是在您的规则 VM 上设置一个 属性 来公开相关的视图名称。如果您更像是一个纯粹主义者,并且希望将这些知识排除在 VM 之外,那么您可以实施一种机制,在该机制中,您可以使用相应视图的名称注册所有规则 VM(例如,在应用程序启动期间)。这可以像 Dictionary
一样简单。在 TreeView 中选择规则 VM 时,您只需查找相应的视图名称以在 RequestNavigate()
调用中使用。
@Andrew 走在正确的轨道上。首先,除非您的架构绝对需要,否则无需将您的模型包装在 ViewModel 中。我猜它不会。完成此任务的最简单方法是使用 InvokeCommandAction 响应所选项目更改事件。然后执行将导航到所需视图的命令。使用所选项目作为参数来确定您要查找的视图。导航时,您还可以使用 NavigationParameters 将所选项目作为参数传递,并在目标上使用 INavigationAware 以便在 OnNavigatedTo 方法中获取该参数。