2

在我的应用程序模型中,我有一个“父母”列表,每个“父母”都引用一个“孩子”列表(例如,一个足球队列表,每个足球队都包含一个球员列表)。

我在树视图中可视化这个列表。我为树创建了一个视图模型类,为足球队创建了一个视图模型类(我们称之为“footballteamViewModel”)。树的类包含带有 footballteamViewModel-items 的 ObservableCollection。树的项目源是这个 ObservableCollection。在初始化期间,我为模型中的每个足球队创建一个对应的 footballteamViewModel 对象并将其添加到 ObservableCollection。

问题是,我的模型中的足球队列表可以从树的外部进行更改,并且我希望更新树。因此,如果有人从我的模型列表中删除了一个足球队,我将不得不删除我的足球队视图模型项目的 ObservableCollection 中的相应项目。

我无法将模型中的足球队列表直接绑定到视图。因此,每次更改模型中的集合时,我都必须以某种方式更新 ViewModel 中的 ObservableCollection。

我处理这个问题的方法是在模型中使用 ObservableCollection 并注册到 ViewModel 中的 collectionChanged 事件,以便在模型集合发生更改时更新我的​​ ViewModel(footballteamViewModel 对象的 Observable 集合)。但这并不“正确”。有没有更好的办法?

在键入此内容时,我发现另一篇文章描述了完全相同的问题:WPF/MVVM: Delegating a domain Model collection to a ViewModel。那里的答案鼓励我,我解决这个问题的方式并不是完全错误的,但我仍然想知道是否还有另一种方法。

编辑:从您提供的第一个答案中,我假设我的问题没有明确的答案。他们都很有帮助,所以值得一读。我只参考 Bindable Linq/Continous Linq/Optics 框架来标记答案,因为我认为它会帮助其他最容易被我的问题绊倒的人。

4

4 回答 4

3

这是 MVVM 更令人讨厌的地方之一。

我前一段时间做过的一件事是创建一个ViewModelCollection<T>继承ObservableCollection<T>并具有修改器方法(添加、删除)的方法,它们对两个集合执行操作,如下所示:

    public interface IViewModel<T>
{
    T WrappedModel { get; }
}

public class ViewModelCollection<T,M> : ObservableCollection<T,M> where T : IViewModel<M>
{
    private IList<M> _baseCollection;

    public ViewModelCollection(IList<T> baseCollection)
    {
        _baseCollection = baseCollection;
    }

    public override void Add(T objectToAdd)
    {
        IViewModel<M> vm = objectToAdd as IViewModel<M>;
        if (vm != null)
        {
            this.Add(objectToAdd);
            _baseCollection.Add(vm.WrappedModel);
        }
    }

    public override void Remove(T objectToRemove)
    {
        IViewModel<M> vm = objectToRemoveas IViewModel<M>;
        if (vm != null)
        {
            this.Remove(objectToRemove);
            _baseCollection.Remove(vm.WrappedModel);
        }
    }
}

现在我根本不这样做,我只是使用 Castle Proxies,将 INotifyPropertyChanged 功能添加到我的模型中 - 节省了大量样板代码!

请注意,我没有测试代码,只是从内存中输入的。

于 2012-05-04T09:47:05.583 回答
2

您说您不能将模型集合直接绑定到视图(这意味着视图模型需要ObservableCollection使用模型集合包含的内容的副本制作自己的),另外,当模型集合更改时需要实时更新视图(这意味着模型需要将此类更改通知视图模型,并且视图模型需要更新其内部副本)。

所有这一切并没有留下太多的回旋余地。一种可能有趣的变体是将模型的集合设置为 read/write IEnumerable,在这种情况下,模型的消费者将被迫在需要修改集合时将其与新实例交换。作为回报,可以简化视图模型的“保持同步”代码,并且可以通过INotifyPropertyChanged集合属性触发同步。

于 2012-05-04T09:42:16.370 回答
1

迟到了,但可能会帮助其他人...

阅读这个关于这个主题的优秀的 3 部分博客文章系列。
第 3 部分是关于集合并展示了一些解决方案 - 对我有很大帮助

MVVM:包装还是不包装?ViewModel 应该包装多少 Model?

于 2012-10-10T02:52:04.447 回答
1

您的解决方案完全没有错,但是有一些库可以帮助您更轻松地实现它,例如 BindableLinq、ContinuousLinq 或 Obtics。你在这里有一个关于他们的讨论。可悲的是,它们似乎都没有进一步发展。

我对 Clinq 的个人体验非常好,我仍然使用它,应该适用于您的情况。

于 2012-05-04T09:43:19.967 回答