首页 文章

MVVM概念用于集合和父/子关系

提问于
浏览
2

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

我在树视图中可视化此列表 . 我为树创建了一个viewmodel-class,为footballteam创建了一个viewmodel-class(让我们称之为“footballteamViewModel”) . 树的类包含一个带有footballteamViewModel-items的ObservableCollection . 树的items-source是ObservableCollection . 在初始化期间,我为模型中的每个足球队员创建一个相应的footballteamViewModel对象,并将其添加到ObservableCollection中 .

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

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

我处理这个问题的方法是在模型中使用ObservableCollection并注册到ViewModel中的collectionChanged-event,这样我就可以在更改模型集合时更新我的ViewModel(footballteamViewModel对象的Observable集合) . 但这感觉并不“正确” . 有没有更好的办法?

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

编辑:从你提供的第一个答案我认为我的问题没有明确的答案 . 他们都很有帮助,所以值得一读 . 我只是通过引用Bindable Linq / Continous Linq / Optics框架来标记答案,因为我认为这将有助于其他最能绊倒我的问题的人 .

4 回答

  • 1

    您的解决方案完全没有错,但有一些库可以帮助您更轻松地实现它,如BindableLinq,ContinuousLinq或Obtics . 你对他们有一个错觉here . 可悲的是,他们似乎都没有进一步发展 .

    我对Clinq的个人经历非常好,我仍然使用它,应该适合您的情况 .

  • 1

    这是MVVM中比较讨厌的地方之一 .

    我之前做过的一件事就是创建一个 ViewModelCollection<T> ,它继承 ObservableCollection<T> 并具有修改方法(Add,Remove),它们对两个集合执行操作,如下所示:

    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功能添加到我的模型中 - 节省了大量的样板代码!

    请注意,我还没有测试过代码,只是从内存中输入了代码 .

  • 3

    您说您无法将模型集合直接绑定到视图(这意味着视图模型需要使用模型集合包含的副本创建自己的 ObservableCollection ),此外视图需要在模型集合时实时更新更改(这意味着模型需要通知viewmodel此类更改,并且viewmodel需要更新其内部副本) .

    所有这些都不是一个读/写 IEnumerable ,在这种情况下,只要需要修改集合,模型的使用者就会被迫用新实例交换它 . 作为回报,可以简化viewmodel的"stay in sync"代码,并且可以通过集合属性上的 INotifyPropertyChanged 触发同步 .

  • 2

    晚了,但可能有助于其他人...

    阅读这篇关于这个主题的优秀3部分博客文章系列 .
    第3部分是关于收藏并展示了一些解决方案 - 帮助了我很多

    MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model?

相关问题