Как превратить ObservableCollection в коллекцию оболочек, чтобы отслеживать изменения?
Я думаю, что это довольно простой вопрос, но я все еще не могу найти лучшего решения для него. Поэтому после исследования этой темы я подумал задать этот вопрос здесь, чтобы получить экспертное мнение.
В основном я работаю над приложением WPF и определил GenericObserableCollection<T>
реализации ObservableCollection<T>
и большинство коллекций реализуют его, чтобы иметь стандартный подход во всем проекте.
[Serializable]
[CollectionDataContract]
public class GenericObservableCollection<T> : ObservableCollection<T>
{
public GenericObservableCollection() { }
public GenericObservableCollection(IEnumerable<T> collection)
: base(collection) { }
}
[Serializable]
[CollectionDataContract]
public class GenericRuleCollection : GenericObservableCollection<IRule>
{
public GenericRuleCollection() { }
public GenericRuleCollection(IEnumerable<IRule> collection)
: base(collection) { }
}
Сначала все было хорошо, но позже, когда появилась Entity Framework, мне пришлось резко изменить дизайн домена, потому что EF требует разоблачения ICollection<T>
для картирования. В тот момент я был в замешательстве, сохраняя минимальные изменения и адаптируясь к EF, потому что был новичком в этом.
Позже после исследования я наткнулся на несколько хороших статей, посвященных этому сценарию.
- Предоставление свойств частной коллекции в Entity Framework
- Отображение, но не отображение ICollections в Entity Framework
Я применил тот же подход при создании домена приложения ChildrenStorage
держать ICollection<GenericRule>
как требование к EF.
Сейчас я ищу умный и элегантный подход, чтобы сохранить обе мои коллекции, т.е. ChildrenStorage
а также Children
коллекция в синхронизации, когда элементы добавляются и / или удаляются. поскольку Children
коллекция - это то, что будет изменено через пользовательский интерфейс, поэтому я хочу отслеживать любые изменения, сделанные в Children
и хочет синхронизировать ChildrenStorage
,
[Serializable]
[DataContract]
public abstract class GenericContainerRule : GenericRule
{
protected GenericContainerRule() : this(null)
{
ChildrenStorage = new List<GenericRule>();
}
protected GenericContainerRule(string name) : base(name)
{
ChildrenStorage = new List<GenericRule>();
}
public void AddChild(IRule rule)
{
ChildrenStorage.Add(rule as GenericRule);
_children = new GenericRuleCollection(ChildrenStorage);
OnPropertyChanged(nameof(Children));
}
public class OrMappings
{
public static Expression<Func<GenericContainerRule, ICollection<GenericRule>>> ChildrenAccessor = t => t.ChildrenStorage;
}
[DataMember]
protected ICollection<GenericRule> ChildrenStorage { get; set; }
private GenericRuleCollection _children;
public GenericRuleCollection Children => _children ?? (_children = new GenericRuleCollection(ChildrenStorage));
private GenericRuleCollection _children;
[DataMember]
public virtual GenericRuleCollection Children
{
get { return _children; }
private set { SetProperty(ref _children, value); }
}
}
1 ответ
Я не думаю, что полностью понимаю, о чем вы спрашиваете, но когда вы говорите о "коллекциях отслеживания изменений" как обертке коллекции, эта статья может вам подойти. В настоящее время я использую его для своего последнего дипломного проекта. Я поставил ссылку на него в конце.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
namespace Core
{
public interface IValidatableTrackingObject :
IRevertibleChangeTracking,
INotifyPropertyChanged
{
bool IsValid { get; }
}
public class ChangeTrackingCollection<T> : ObservableCollection<T>, IValidatableTrackingObject
where T : class, IValidatableTrackingObject
{
private IList<T> _originalCollection;
private ObservableCollection<T> _addedItems;
private ObservableCollection<T> _removedItems;
private ObservableCollection<T> _modifiedItems;
public ChangeTrackingCollection(IEnumerable<T> items)
: base(items)
{
_originalCollection = this.ToList();
AttachItemPropertyChangedHandler(_originalCollection);
_addedItems = new ObservableCollection<T>();
_removedItems = new ObservableCollection<T>();
_modifiedItems = new ObservableCollection<T>();
this.AddedItems = new ReadOnlyObservableCollection<T>(_addedItems);
this.RemovedItems = new ReadOnlyObservableCollection<T>(_removedItems);
this.ModifiedItems = new ReadOnlyObservableCollection<T>(_modifiedItems);
}
public ReadOnlyObservableCollection<T> AddedItems { get; private set; }
public ReadOnlyObservableCollection<T> RemovedItems { get; private set; }
public ReadOnlyObservableCollection<T> ModifiedItems { get; private set; }
public bool IsChanged => AddedItems.Count > 0
|| RemovedItems.Count > 0
|| ModifiedItems.Count > 0;
public bool IsValid => this.All(t => t.IsValid);
public void AcceptChanges()
{
_addedItems.Clear();
_removedItems.Clear();
_modifiedItems.Clear();
foreach (var item in this)
{
item.AcceptChanges();
}
_originalCollection = this.ToList();
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsChanged)));
}
public void RejectChanges()
{
foreach (var removedItem in _removedItems.ToList()) this.Add(removedItem);
foreach (var addedItem in _addedItems.ToList()) this.Remove(addedItem);
foreach (var modifiedItem in _modifiedItems.ToList()) modifiedItem.RejectChanges();
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsChanged)));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
var added = this.Where(current => _originalCollection.All(orig => orig != current));
var removed = _originalCollection.Where(orig => this.All(current => current != orig));
var modified = this.Except(added).Except(removed).Where(item => item.IsChanged).ToList();
AttachItemPropertyChangedHandler(added);
DetachItemPropertyChangedHandler(removed);
UpdateObservableCollection(_addedItems, added);
UpdateObservableCollection(_removedItems, removed);
UpdateObservableCollection(_modifiedItems, modified);
base.OnCollectionChanged(e);
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsChanged)));
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsValid)));
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(IsValid))
{
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsValid)));
}
else
{
var item = (T)sender;
if (_addedItems.Contains(item))
{
return;
}
if (item.IsChanged)
{
if (!_modifiedItems.Contains(item))
{
_modifiedItems.Add(item);
}
}
else
{
if (_modifiedItems.Contains(item))
{
_modifiedItems.Remove(item);
}
}
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsChanged)));
}
}
private void AttachItemPropertyChangedHandler(IEnumerable<T> items)
{
foreach (var item in items)
{
item.PropertyChanged += ItemPropertyChanged;
}
}
private void DetachItemPropertyChangedHandler(IEnumerable<T> items)
{
foreach (var item in items)
{
item.PropertyChanged -= ItemPropertyChanged;
}
}
private void UpdateObservableCollection(ObservableCollection<T> collection, IEnumerable<T> items)
{
collection.Clear();
foreach (var item in items)
{
collection.Add(item);
}
}
}
}
https://github.com/PFC-acl-amg/GamaPFC/blob/master/GamaPFC/Core/ChangeTrackingCollection.cs