Wpf 根据对象类型将视图注入ItemsControl

Wpf 根据对象类型将视图注入ItemsControl,wpf,inheritance,mvvm,view,viewmodel,Wpf,Inheritance,Mvvm,View,Viewmodel,我有一个服务返回Party类型的数组。党有两个亚类型,个人和组织。我从视图模型在WPF应用程序(Prism、MVVM)中使用此服务。在该视图模型的构造函数中,我填充了一个类型为Party的可观察集合: public PhoneBookViewModel(IPhoneBookService phoneBookProxy) { _phoneBookProxy = phoneBookProxy; var parties = _phoneBookProxy.GetAllParties(

我有一个服务返回Party类型的数组。党有两个亚类型,个人和组织。我从视图模型在WPF应用程序(Prism、MVVM)中使用此服务。在该视图模型的构造函数中,我填充了一个类型为Party的可观察集合:

public PhoneBookViewModel(IPhoneBookService phoneBookProxy)
{
    _phoneBookProxy = phoneBookProxy;

    var parties = _phoneBookProxy.GetAllParties();
    _parties = new ObservableCollection<Party>(parties.ToList());
}
公共电话簿视图模型(IPhoneBookService phoneBookProxy) { _phoneBookProxy=phoneBookProxy; var parties=_phoneBookProxy.GetAllParties(); _parties=新的可观测集合(parties.ToList()); } 到目前为止还不错。在我的PhoneBookView中,我有一个绑定到此集合的ItemsControl。在此控件中,我希望使用另一个视图(及其视图模型)渲染各方。因此,当Party为Person类型时,注入PersonView并将Party对象传递给PersonViewModel的构造函数,而当Party为Organization类型时,则呈现OrganizationView,以此类推。。。你明白了吗

但我不知道如何在XAML中实现这一点。有什么想法吗? 这可能不是最好的方法,所以如果你能推荐一种更好的方法,请告诉我:-)


谢谢

为您的数据类型配置一个数据模板,以呈现xaml。

让我们从视图到模型进行检查:


假设我们有两种不同类型的视图,一种类型的视图模型:

ViewA-->使用DataTempate/DataTemplateSelector在items控件内创建,绑定>到ViewModelA

ViewB-->使用DataTempate/DataTemplateSelector在items控件内创建,绑定到ViewModelA

如果两个视图都绑定到同一视图模型,则最终将得到相同的视图


让我们使用2种不同类型的视图和2种不同类型的视图模型重试:

ViewA-->使用DataTempate/DataTemplateSelector在items控件内创建,绑定到ViewModelA-->绑定到ModelA

ViewB-->使用DataTempate/DataTemplateSelector在items控件内创建,绑定到ViewModelB-->绑定到ModelB

这是可能的


现在,如果您对视图模型和以下模型进行建模(伪代码):

公共电话簿视图模型
{
公共电话簿视图模型()
{
_parties=新的观测值集合();
}
私人电话簿(dataContext),;
//这是VM用于访问模型的属性
公共电话簿数据上下文
{
获取{return\u dataContext;}
设置
{
如果(_dataContext!=null)
{
_dataContext.Parties.CollectionChanged-=OnModelPartiesChanged;
}
_数据上下文=值;
如果(_dataContext!=null)
{
_dataContext.Parties.CollectionChanged+=OnModelPartiesChanged;
}
}
}
私人可观测收集方;
//这是视图用于访问VM参与方集合的属性
公共ObservableCollection PartiesViewModels{get{return\u parties;}
ModelPartiesChanged上的私有无效(…)
{
//在PartiesViewModels中添加/删除虚拟机
}
}
//模型
公用电话簿
{
公共电话簿()
{
_parties=新的观测值集合();
}
私人可观测收集方;
//这是VM用于访问模型各方的属性
公共可观察集合方{get{return\u Parties;}
}
PublicPersonViewModel:PartyViewModel
{
new Person DataContext{get;set;}
}
公共PartyViewModel
{
公共方数据上下文{get;set;}
}
然后您将获得每个模型项的正确VM类型, 视图将绑定到VM项,而不是模型项


视图的数据模板:

<DataTemplate x:Target={x:Type myVmNamespace:PersonViewModel}">
    <PersonView/>
</DataTemplate>

<DataTemplate x:Target={x:Type myVmNamespace:GroupViewModel}">
    <GroupView/>
</DataTemplate>

视图的itemscontrol:

<!-- Bind to Parties property of PhoneBookVM -->
<!-- Uses datatemplates for items -->
<ListView ItemsSource={Binding Parties}"/>


如果您使用的是Prism和MVVM,那么您就是将命令绑定到所有参与方的ItemsControl

此命令的类型为
DelegateCommand
。在命令正在执行的委托内部,如下所示:

private void PartyNavigate(Party party)
只需检查参与方是否属于任何子类型,并在您的
RegionManager
区域中调用
RequestNavigate
,即可进入特定视图


然后,如何传递实际上下文将成为一个问题,您可以查看Prism附带的MVVM RI,它以
StateHandler
的形式提供了很好的解决方案,或者您可以构建自己的集中式数据管理器,在其中保存这些内容的状态,除了缓存您从Web服务获得的东西,等等。在使用WPF和WCF构建智能客户端2年后,我可以告诉您,您最终需要构建自己的DataManager,如果您已经在使用EntityFramework,并且大部分内容都是通过EDM生成的,那么这就不算什么了。

您的项目控制项目资源由PhoneBookViewModel填充。因此,剩下的唯一一件事就是告诉WPF如何呈现此集合的每个项。这可以通过创建数据模板轻松实现

 <DataTemplate DataType="{x:Type PersonViewModel}"> 
     <MyPersonView/> 
 </DataTemplate>


我没有详细说明管道的所有细节(例如,集合后面的只读字段,以使OnCollectionChanged注册到正确的集合)。但是这种方法确实很有效(已经使用过很多次)。这对我来说没有多大意义:-)PhoneBookViewModel中的PhoneBook数据上下文是什么,它与两部分ViewModel有什么关系?我不明白。添加了更多细节。基本上,虚拟机连接到M与V连接到虚拟机的方式类似。谢谢Danny。我现在很忙,但我会尽快看这个。只是想让你知道-我没有忘记:-)怎么做?如何将参数传递给视图模型的构造函数?是的,但我需要将特定实例传递给视图。我该怎么做?
 <DataTemplate DataType="{x:Type PersonViewModel}"> 
     <MyPersonView/> 
 </DataTemplate>