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