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

3

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

public PhoneBookViewModel(IPhoneBookService phoneBookProxy)
{
    _phoneBookProxy = phoneBookProxy;

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

到目前为止一切顺利。在我的PhoneBookView中,我有一个ItemsControl绑定到这个集合。在这个控件中,我想使用另一个视图(和它的视图模型)来呈现每个Party。所以当Party是Person类型时,注入PersonView并将Party对象传递给PersonViewModel的构造函数,当Party是Organization类型时,呈现OrganizationView,依此类推......你有画面了吗?
但我不知道如何在XAML中实现这一点。有什么想法吗?这可能不是最好的方法,如果您能推荐更好的方法,请 enlighten me :-)
谢谢!
4个回答

1
让我们从模型的角度来审视这个问题:
假设我们有两种不同类型的视图,一种视图模型:

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

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

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

让我们再尝试一次,使用2种不同类型的视图和2种不同类型的视图模型:

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

ViewB --> 在项控件中使用DataTempate/DataTemplateSelector创建,绑定到ViewModelB --> 绑定到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}"/>

我没有详细说明所有的细节(例如,在集合后面保留只读字段,以便将OnCollectionChanged注册到正确的集合)。但这种方法确实很有效(我已经使用过很多次)。 - Danny Varod
这对我来说不太有意义 :-) 你的PhoneBookViewModel中的PhoneBook DataContext是什么,它与两个PartyViewModels有什么关系?我不明白。 - Tommy Jakobsen
添加更多细节。基本上,VM与M的连接方式类似于V与VM的连接方式。 - Danny Varod
谢谢 Danny。我现在很忙,但我会尽快查看它。只是想让你知道 - 我没有忘记它 :-) - Tommy Jakobsen

0
如果您正在使用Prism和MVVM,那么您会将一个命令与所有Party绑定到您的ItemsControl上。
这个命令的类型将是DelegateCommand<Party>。在命令执行的委托内部,它看起来像这样:
private void PartyNavigate(Party party)

只需检查派对是否为任何子类型,并在您的RegionManager区域上调用RequestNavigate到特定视图。

然后问题就变成了如何传递实际上下文,您可以查看Prism附带的MVVM RI,它具有非常好的方法,以StateHandler的形式呈现,或者您可以构建自己的集中式DataManager,在其中保留这些事物的状态,以及缓存从WebServices获取的内容等。在使用WPF和WCF构建智能客户端2年后,我可以告诉您,您最终需要构建自己的DataManager,如果您已经使用EntityFramework并从EDM生成大部分内容,则不会太麻烦。


0
你的ItemsControl ItemsSource的集合是由PhoneBookViewModel填充的。现在唯一需要做的就是告诉WPF如何呈现该集合中的每个项。只需创建一个DataTemplate即可轻松实现。
 <DataTemplate DataType="{x:Type PersonViewModel}"> 
     <MyPersonView/> 
 </DataTemplate>

是的,但我需要将特定的实例传递给视图。我该怎么做? - Tommy Jakobsen

0
配置一个数据模板,用于呈现 XAML 中的数据类型。

怎么做?你会如何将参数传递给视图模型的构造函数? - Tommy Jakobsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接