我在理解如何基于以下模型构建视图模型时遇到问题
(我将模型简化为更清晰)
public class Hit
{
public bool On { get; set;}
public Track Track { get; set; }
}
public class Track
{
public ObservableCollection<Hit> Hits { get; set; }
public LinearGradientBrush Color { get; set; }
public Pattern Pattern { get; set; }
}
public class Pattern
{
public string Name { get; set; }
public ObservableCollection<Tracks> Tracks { get; set; }
}
现在,我的问题是,如何构建ViewModels ..
我需要通过模型保持原始关系,beacaus我在Pattern上有一个Serialize()方法,将它序列化为XML文件..(带有相关的曲目和命中)
为了能够将模式绑定到用户控件及其嵌套模板,我还应该有一个带有ObservableCollection&lt; TrackViewModel&gt;的PatternViewModel。在它中,对于TrackViewModel和HitViewModel来说也是如此..我需要在不属于业务对象的视图模型上具有自定义表示属性(颜色和更多......)
在视图模型上复制模型的所有关系对我来说似乎不是一件好事...... 并且在编写视图模型时跟踪所有这些关系也更容易出错..
任何人都有更好的方法/解决方案吗?
答案 0 :(得分:3)
我做了一件事,取得了一些成功,就是将ObservableCollection移出模型。这是我的一般模式:
IEnumerable<TModel>
的属性,该属性提供对集合的只读访问权限。使用普通的旧List<TModel>
而不是ObservableCollection作为支持集合。ObservableCollection<TNestedViewModel>
。这为每个不同的ViewModel提供了大量重复的代码,但它是我能够想到的最好的代码。它至少根据您需要的复杂程度进行扩展 - 如果您有一个仅添加的集合,则不必编写太多代码;如果你有一个支持任意重新排序,插入,排序等的集合,那就更有用了。
答案 1 :(得分:2)
我最终使用Joe White提出的解决方案的一部分,方式略有不同
解决方案是将模型保留在开头,并将集合附加到内部集合的CollectionChanged的事件处理程序,例如,PatternViewModel将是:
public class PatternViewModel : ISerializable
{
public Pattern Pattern { get; set; }
public ObservableCollection<TrackViewModel> Tracks { get; set; }
public PatternViewModel(string name)
{
Pattern = new Pattern(name);
Tracks = new ObservableCollection<TrackViewModel>();
Pattern.Tracks.CollectionChanged += new NotifyCollectionChangedEventHandler(Tracks_CollectionChanged);
}
void Tracks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Track track in e.NewItems)
{
var position = Pattern.Tracks.IndexOf((Track) e.NewItems[0]);
Tracks.Insert(position,new TrackViewModel(track, this));
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (Track track in e.OldItems)
Tracks.Remove(Tracks.First(t => t.Track == track));
break;
case NotifyCollectionChangedAction.Move:
for (int k = 0; k < e.NewItems.Count; k++)
{
var oldPosition = Tracks.IndexOf(Tracks.First(t => t.Track == e.OldItems[k]));
var newPosition = Pattern.Tracks.IndexOf((Track) e.NewItems[k]);
Tracks.Move(oldPosition, newPosition);
}
break;
}
}
}
所以我可以在视图模型上附加新的颜色/样式/命令以保持我的基本模型清洁
每当我在基本模型集合中添加/删除/移动项目时,视图模型集合将保持彼此同步
幸运的是,我不需要在我的应用程序中管理大量对象,因此重复的数据和性能不会成为问题
我不太喜欢它,但它运行良好,并且它不是大量工作,只是视图模型的事件处理程序,包含其他视图模型集合(在我的情况下,一个用于PatternViewModel同步TrackViewModels和TrackViewModel上的另一个管理HitViewModel)
仍然对你的想法或更好的想法感兴趣=)
答案 2 :(得分:1)
我认为我遇到了同样的问题,如果你这样做,就像“PatternViewModel with ObservableCollection&lt; TrackViewModel&gt;”您也会因为开始复制数据而对性能产生巨大影响。
我的方法是为您的示例构建一个带有ObservableCollection&lt; Track&gt;的PatternViewModel。这与MVVM没有矛盾,因为视图绑定到集合。
这样可以避免重复关系。
答案 3 :(得分:0)
我一直在考虑的一个解决方案,虽然我不确定它在实践中是否能完美运行,但是使用转换器来创建模型周围的视图模型。
因此,在您的情况下,您可以将Tracks
直接绑定到(作为示例)列表框,并使用从Track创建新TrackViewModel
的转换器。你所看到的所有控件都是TrackViewModel
对象,所有模型都会看到其他模型。
我不确定这个想法的动态更新,但我还没试过。