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

时间:2011-04-17 13:46:21

标签: wpf inheritance mvvm view viewmodel

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

public PhoneBookViewModel(IPhoneBookService phoneBookProxy)
{
    _phoneBookProxy = phoneBookProxy;

    var parties = _phoneBookProxy.GetAllParties();
    _parties = new ObservableCollection<Party>(parties.ToList());
}

到目前为止一切顺利。在我的PhoneBookView中,我有一个绑定到此集合的ItemsControl。在此控件中,我想使用另一个View(及其视图模型)渲染每个Party。所以当Party是Person类型时,注入PersonView并将Party对象传递给PersonViewModel的构造函数,当Party类型为Organization时,渲染OrganizationView,等等......你得到图片(或?)。

但我无法弄清楚如何在XAML中执行此操作。有任何想法吗? 这可能不是最好的方法,所以如果你能推荐一个更好的方法,请赐教: - )

谢谢!

4 个答案:

答案 0 :(得分:1)

让我们从模型的角度来看待这个:


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

  

ViewA - &gt;使用DataTempate / DataTemplateSelector在Bin控件中创建,Binded&gt;到ViewModelA

     

ViewB - &gt;使用DataTempate / DataTemplateSelector在一个项目控件中创建,Binded到ViewModelA

如果两个视图绑定到同一视图模型,您最终会得到相同的视图。


让我们再尝试两种不同类型的视图和两种不同类型的视图模型:

  

ViewA - &gt;使用DataTempate / DataTemplateSelector在一个项目控件中创建,Binded到ViewModelA - &gt;绑定到ModelA

     

ViewB - &gt;使用DataTempate / DataTemplateSelector在项目控件中创建,Binded到ViewModelB - &gt;绑定到ModelB

这是可能的。


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

public PhoneBookViewModel
{
    public PhoneBookViewModel()
    {
        _parties = new ObservalbeCollection<PartyViewModel>();
    }

    private PhoneBook _dataContext;

    // This is the property the VM uses to access the model
    public PhoneBook DataContext
    {
        get { return _dataContext; }
        set
        {
            if (_dataContext != null)
            {
                _dataContext.Parties.CollectionChanged -= OnModelPartiesChanged;
            }
            _dataContext = value;
            if (_dataContext != null)
            {
                _dataContext.Parties.CollectionChanged += OnModelPartiesChanged;
            }
        }
    }

    private ObservableCollection<PartyViewModel> _parties;

    // This is the property the view uses to access the collection of VM parties
    public ObservableCollection<PartyViewModel> PartiesViewModels { get { return _parties; } }

    private void OnModelPartiesChanged(...)
    {
        // Add/remove VMs to/from PartiesViewModels here
    }
}

// Model
public PhoneBook
{
    public PhoneBook()
    {
        _parties = new ObservalbeCollection<Party>();
    }

    private ObservableCollection<Party> _parties;

    // This is the property the VM uses to access the model's parties
    public ObservableCollection<Party> Parties { get { return _parties; } }
}

public PersonViewModel : PartyViewModel
{
    new Person DataContext { get; set; }
}

public PartyViewModel
{
    public Party DataContext { 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}"/>

答案 1 :(得分:0)

为数据类型配置数据模板以呈现xaml。

答案 2 :(得分:0)

如果您正在使用Prism和MVVM,那么您将命令绑定到与所有缔约方的ItemsControl。

此命令的类型为DelegateCommand<Party>。在执行命令的Delegate内部,如下所示:

private void PartyNavigate(Party party)

只需检查该方是否属于任何子类型,并在RequestNavigate的区域内拨打RegionManager特定视图。

如果您传递实际上下文将成为一个问题,您可以查看Prism附带的MVVM RI,它以StateHandler的形式对此非常好,或者你可以构建您自己的集中式DataManager,您可以在其中保存这些内容的状态,以及从WebServices获取的缓存等。使用WPF和WCF构建智能客户端2年后,我可以告诉您最终需要构建自己的DataManager如果您已经在使用EntityFramework并且从EDM中生成了大部分内容,那么这将不是什么大不了的事。

答案 3 :(得分:0)

您的ItemsControl ItemsSource的集合由PhoneBookViewModel填充。因此,唯一剩下的就是告诉WPF应该如何呈现此集合的每个项目。这可以通过创建DataTemplate轻松实现。

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