在我的申请模型中,我有一个“父母”列表,每个“父母”都会列出一个“孩子”列表(例如,每个包含一个玩家列表的足球队列表)。
我在树状视图中可视化此列表。我为树创建了一个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框架来标记答案,因为我认为这将有助于其他最能绊倒我的问题的人。答案 0 :(得分: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功能添加到我的模型中 - 节省了大量的样板代码!
请注意,我没有测试过代码,只是从内存中输入代码。
答案 1 :(得分:2)
您说您无法将模型集合直接绑定到视图(这意味着视图模型需要使用模型集合包含的副本创建自己的ObservableCollection
),此外视图需要在模型集合发生更改时进行实时更新(这意味着模型需要通知viewmodel此类更改,并且viewmodel需要更新其内部副本)。
所有这些并没有留下太多的摆动空间。可能有趣的一个变体是使模型的集合成为读/写IEnumerable
,在这种情况下,模型的消费者将被迫在需要修改集合时将其与新实例交换。作为回报,可以简化视图模型的“保持同步”代码,并且可以通过集合属性上的INotifyPropertyChanged
触发同步。
答案 2 :(得分:1)
你的解决方案完全没有错,但是有一些库可以帮助你更轻松地实现它,比如BindableLinq,ContinuousLinq或Obtics。你对他们的看法here。可悲的是,他们似乎都没有进一步发展。
我对Clinq的个人经历非常好,我仍然使用它,应该适合您的情况。
答案 3 :(得分:1)
迟到了,但可能有助于其他人......
阅读这篇关于这个主题的优秀3部分博客文章系列 第3部分是关于收藏并展示了一些解决方案 - 帮助我很多
MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model?