是否有一种标准化的方法可以将一组Model对象与C#和WPF中匹配的ModelView对象的一组同步?我正在寻找某种类,它会保持以下两个集合同步,假设我只有几个苹果,我可以将它们全部留在内存中.
另一种说法,我想确保如果我将Apple添加到Apples集合中,我想将AppleModelView添加到AppleModelViews集合中.我可以通过收听每个集合的CollectionChanged事件来编写自己的事件.这似乎是一种常见的情况,比我聪明的人定义了"正确的方法"来做到这一点.
public class BasketModel
{
public ObservableCollection<Apple> Apples { get; }
}
public class BasketModelView
{
public ObservableCollection<AppleModelView> AppleModelViews { get; }
}
Run Code Online (Sandbox Code Playgroud)
Sam*_*ell 64
我使用延迟构建的自动更新集合:
public class BasketModelView
{
private readonly Lazy<ObservableCollection<AppleModelView>> _appleViews;
public BasketModelView(BasketModel basket)
{
Func<AppleModel, AppleModelView> viewModelCreator = model => new AppleModelView(model);
Func<ObservableCollection<AppleModelView>> collectionCreator =
() => new ObservableViewModelCollection<AppleModelView, AppleModel>(basket.Apples, viewModelCreator);
_appleViews = new Lazy<ObservableCollection<AppleModelView>>(collectionCreator);
}
public ObservableCollection<AppleModelView> Apples
{
get
{
return _appleViews.Value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下内容ObservableViewModelCollection<TViewModel, TModel>:
namespace Client.UI
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.Linq;
public class ObservableViewModelCollection<TViewModel, TModel> : ObservableCollection<TViewModel>
{
private readonly ObservableCollection<TModel> _source;
private readonly Func<TModel, TViewModel> _viewModelFactory;
public ObservableViewModelCollection(ObservableCollection<TModel> source, Func<TModel, TViewModel> viewModelFactory)
: base(source.Select(model => viewModelFactory(model)))
{
Contract.Requires(source != null);
Contract.Requires(viewModelFactory != null);
this._source = source;
this._viewModelFactory = viewModelFactory;
this._source.CollectionChanged += OnSourceCollectionChanged;
}
protected virtual TViewModel CreateViewModel(TModel model)
{
return _viewModelFactory(model);
}
private void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
for (int i = 0; i < e.NewItems.Count; i++)
{
this.Insert(e.NewStartingIndex + i, CreateViewModel((TModel)e.NewItems[i]));
}
break;
case NotifyCollectionChangedAction.Move:
if (e.OldItems.Count == 1)
{
this.Move(e.OldStartingIndex, e.NewStartingIndex);
}
else
{
List<TViewModel> items = this.Skip(e.OldStartingIndex).Take(e.OldItems.Count).ToList();
for (int i = 0; i < e.OldItems.Count; i++)
this.RemoveAt(e.OldStartingIndex);
for (int i = 0; i < items.Count; i++)
this.Insert(e.NewStartingIndex + i, items[i]);
}
break;
case NotifyCollectionChangedAction.Remove:
for (int i = 0; i < e.OldItems.Count; i++)
this.RemoveAt(e.OldStartingIndex);
break;
case NotifyCollectionChangedAction.Replace:
// remove
for (int i = 0; i < e.OldItems.Count; i++)
this.RemoveAt(e.OldStartingIndex);
// add
goto case NotifyCollectionChangedAction.Add;
case NotifyCollectionChangedAction.Reset:
Clear();
for (int i = 0; i < e.NewItems.Count; i++)
this.Add(CreateViewModel((TModel)e.NewItems[i]));
break;
default:
break;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可能不完全理解您的要求,但是我处理类似情况的方式是在ObservableCollection上使用CollectionChanged事件,并根据需要简单地创建/销毁视图模型.
void OnApplesCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Only add/remove items if already populated.
if (!IsPopulated)
return;
Apple apple;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
apple = e.NewItems[0] as Apple;
if (apple != null)
AddViewModel(asset);
break;
case NotifyCollectionChangedAction.Remove:
apple = e.OldItems[0] as Apple;
if (apple != null)
RemoveViewModel(apple);
break;
}
}
Run Code Online (Sandbox Code Playgroud)
在ListView中添加/删除大量项目时可能会出现一些性能问题.
我们通过以下方式解决了这个问题:扩展ObservableCollection以使用AddRange,RemoveRange,BinaryInsert方法并添加通知其他人正在更改集合的事件.与扩展的CollectionViewSource一起,当集合被更改时临时断开源,它可以很好地工作.
HTH,
丹尼斯