最近,我对View Models (VM)的看法有些不太对劲。
就像this guy一样,我得出的结论是,我需要在VM上公开的集合通常包含与在业务对象上公开的集合不同的类型。
因此,这两种类型之间必须存在双向映射或转换。(让事情更复杂的是,在我的项目中,这个数据是“实时的”,这样只要你改变一个属性,它就会被传输到其他计算机上)
我几乎可以使用像Truss这样的框架来处理这个概念,尽管我怀疑其中会有一个令人讨厌的惊喜。
不仅必须转换对象,还需要在这两个集合之间进行同步。(让事情更复杂的是,我可以考虑VM集合可能是业务对象集合的子集或联合的情况,而不是简单的1:1同步)。
我可以看到如何做一个单向的“实时”同步,使用一个复制的ObservableCollection或类似CLINQ的东西。
然后问题就变成了:创建/删除项目的最佳方式是什么?
双向同步似乎不在卡片上--我没有找到这样的例子,唯一一个远程支持这样的东西的类是ListCollectionView。将双向同步添加回业务对象集合是一种明智的方式吗?
我见过的所有样本似乎都没有解决过如此“复杂”的问题。
所以我的问题是:你如何解决这个问题?有没有什么技术可以更新VM中的模型集合?对此最好的通用方法是什么?
发布于 2010-02-10 05:26:57
我也在为通过MVVM使用WPF的两个集合的双向同步而苦苦挣扎。关于这个问题,我在MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model? (Part 1)和MVVM: To Wrap or Not to Wrap? Should ViewModels wrap collections too? (Part 2)上发了博客,包括一些显示双向同步的示例代码。然而,正如帖子中指出的那样,实现并不理想。我会将其限定为概念证明。
我喜欢Alex_P发布的BLINQ、CLINQ和Obtics框架。这是一种很好的方法来获得同步行为的一面。也许另一边(从VM到Model)可以通过另一条路径实现?我刚刚在我的博客上发布了part 3,讨论了其中的一些内容。
在我看来,在LINQ语句将数据投影到新结构的情况下,不支持通过BLINQ和CLINQ进行双向。
但是,在LINQ查询返回与基础集合相同的数据类型的情况下,看起来CLINQ可能支持双向同步。这更像是一种过滤场景,与ViewModel包装模型中数据的用例不匹配。
发布于 2010-02-06 00:22:41
就我个人而言,我在我的模型和视图模型中使用ObservableCollection。
class Model
{
public ObservableCollection<Foo> Foos;
}
class ViewModel
{
public Model Model;
public ObservableCollection<FooView> Foos;
public ViewModel()
{
Model.Foos.CollectionChanged += OnModelFoosCollection_CollectionChanged;
}
void OnModelFoosCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Foo re;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
re = e.NewItems[0] as Foo;
if (re != null)
AddFoo(re); //For other logic that may need to be applied
break;
case NotifyCollectionChangedAction.Remove:
re = e.OldItems[0] as Foo;
if (re != null)
RemoveFoo(re);
break;
case NotifyCollectionChangedAction.Reset:
Foos.Clear();
/* I have an AddRange in an ObservableCollection-derived class
You could do Model.Foo.ForEach(ree => AddFoo(ree));
*/
var converter =
from ree in Model.Foo
select new FooView(ree);
Reports.AddRange(converter);
break;
default:
//exercise for the reader :)
s_ILog.Error("OnModelFoosCollection_CollectionChangedDid not deal with " + e.Action.ToString());
break;
}
}
void AddFoo(Foo f)
{
Foos.Add(new FooView(f));
}
void RemoveFoo(Foo f)
{
var match = from f in Foos
where f.Model == f //if you have a unique id, that might be a faster comparison
select f;
if(match.Any())
Foos.Remove(match.First());
}
}现在,当您从Model的Foo集合中删除某些内容时,它将自动删除相应的FooView。这与我对这类事情的看法一致。如果我想删除一些东西,Model才是真正需要删除的地方。
这感觉像是有很多代码,但实际上并不是那么多。我相信可以构建一个通用的版本,但我想你最终总是想要处理添加/删除元素的自定义逻辑。
发布于 2010-02-16 07:09:10
我已经编写了一些帮助器类,用于在视图模型对应的here中包装业务对象的可观察集合,也许应该将其扩展为另一种方式。总是在寻找贡献...
https://stackoverflow.com/questions/2207373
复制相似问题