Как превратить 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, потому что был новичком в этом.

Позже после исследования я наткнулся на несколько хороших статей, посвященных этому сценарию.

Я применил тот же подход при создании домена приложения 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

Другие вопросы по тегам