Question

Hi i want to do something like SomeCollection.GetChanges(ItemState.Deleted) and the result should be all removed Items

You can do such things with DataTable. But how to implement this in an List<T> or ObservableCollection<T>?

Is there already a solution for this problem? If not would it be wise to create such a Collection?

Any advice is greatly appreciated

EDIT:

that's my code so far, i have test and fix it now but i still thing there may be a better solution

using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.ComponentModel;

namespace Framework
{
    public enum CollStat
    {
        Unchanged,
        Added,
        Replacer,
        Replaced,
        Deleted,
        Modified
    }

    public class NotifyObservableCollection<T> : ObservableCollection<T> where T : Notifyer
    {
        #region private
        private class _ElementKeeper<T>
        {
            public T Element;
            public CollStat Modification;

            public _ElementKeeper(T element, CollStat Modifi)
            {
                Element = element;
                Modification = Modifi;
            }
        }

        private int _ChangesIdx = 0;
        private bool _Reject = false;

        private Dictionary<int, _ElementKeeper<T>> DicOfChanges = new Dictionary<int, _ElementKeeper<T>>();
        #endregion //private

        #region cTor (3)
        public NotifyObservableCollection() : base() { }
        public NotifyObservableCollection(List<T> list)
            : base(list)
        {
            Subscribe(list);
        }
        public NotifyObservableCollection(IEnumerable<T> collection)
            : base(collection)
        {
            Subscribe(collection.ToList());
        }
        #endregion

        #region ObservableCollection override(2)
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (!_Reject)
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (T item in e.NewItems)
                    {
                        DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Added));
                        _ChangesIdx++;
                    }
                }

                else if (e.Action == NotifyCollectionChangedAction.Replace)
                {
                    foreach (T item in e.OldItems)
                    {
                        DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Replaced));
                        _ChangesIdx++;
                    }

                    foreach (T item in e.NewItems)
                    {
                        DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Replacer));
                        _ChangesIdx++;
                    }

                }

                else if (e.Action == NotifyCollectionChangedAction.Remove)
                {
                    foreach (T item in e.OldItems)
                    {
                        DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Deleted));
                        _ChangesIdx++;
                    }
                }

            Unsubscribe(e.OldItems);
            Subscribe(e.NewItems);
            base.OnCollectionChanged(e);
        }

        protected override void ClearItems()
        {
            foreach (T element in this)
                element.PropertyChanged -= ContainedElementChanged;

            base.ClearItems();
        }

        #region ItemNotification
        private void Subscribe(ICollection iList)
        {
            if (iList != null)
                foreach (T element in iList)
                    element.PropertyChanged += ContainedElementChanged;
        }

        private void Unsubscribe(ICollection iList)
        {
            if (iList != null)
                foreach (T element in iList)
                    element.PropertyChanged -= ContainedElementChanged;
        }

        private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
        {
            var item = sender as T;

            if (DicOfChanges.Count < 1)
            {
                DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Modified));
                _ChangesIdx++;
            }
            else if (!DicOfChanges.Any(x => (x.Value.Element == item && x.Value.Modification == CollStat.Modified)))
            {
                DicOfChanges.Add(_ChangesIdx, new _ElementKeeper<T>(item, CollStat.Modified));
                _ChangesIdx++;
            }          

            OnPropertyChanged(e);
        }
        #endregion //ItemNotification
        #endregion  //ObservableCollection override(2)

        /// <summary>
        /// Accepts all Changes they are made to this Object
        /// </summary>
        public void AcceptChanges()
        {
            DicOfChanges.Clear();
            _ChangesIdx = 0;
        }

        /// <summary>
        /// Undoes
        /// </summary>
        public void RejectChanges()
        {
            _Reject = true;

            for (int i = _ChangesIdx; i >= 0; i--)
            {
                if (DicOfChanges[i].Modification == CollStat.Added)
                    this.Items.Remove(DicOfChanges[i].Element);

                else if (DicOfChanges[i].Modification == CollStat.Deleted)
                    this.Items.Add(DicOfChanges[i].Element);

                else if (DicOfChanges[i].Modification == CollStat.Replacer)
                {
                    var idx = this.Items.IndexOf(DicOfChanges[i - 1].Element);
                    this.Items[idx] = DicOfChanges[i].Element;
                }
            }

            _Reject = false;

            AcceptChanges();
        }


        /// <summary>
        /// Returns a ObservableCollection with Elements they match the CollStat type
        /// </summary>
        /// <param name="stat">CollStat of the elements</param>
        /// <returns>ObservableCollection with the requested Elements</returns>
        public ObservableCollection<T> GetChanges(CollStat stat)
        {
            ObservableCollection<T> CollOfChanges = new ObservableCollection<T>();

            switch (stat)
            {
                case CollStat.Added:
                    //Alle hinzugefügten Elemente auswählen
                    CollOfChanges = CollOfStat(CollStat.Added);

                    //Alle gelöschten Elemente auswählen
                    var Deleted = DicOfChanges.Where(x => (x.Value).Modification == CollStat.Deleted);

                    //Entfernen dieser Elemente sollten sie in CollOfChanges vorhanden sein
                    foreach (KeyValuePair<int, _ElementKeeper<T>> pair in Deleted)
                        if (CollOfChanges.Contains(pair.Value.Element))
                            CollOfChanges.Remove(pair.Value.Element);
                    break;

                case CollStat.Deleted:
                    CollOfChanges = CollOfStat(CollStat.Deleted);
                    break;

                case CollStat.Modified:
                    CollOfChanges = CollOfStat(CollStat.Modified);
                    break;

                case CollStat.Replacer:
                    CollOfChanges = CollOfStat(CollStat.Replacer);
                    break;

                case CollStat.Replaced:
                    CollOfChanges = CollOfStat(CollStat.Replaced);
                    break;

                case CollStat.Unchanged:
                    CollOfChanges = new ObservableCollection<T>(this);

                    var Added = DicOfChanges.Where(x => (x.Value).Modification == CollStat.Added);
                    foreach (KeyValuePair<int, _ElementKeeper<T>> pair in Added)
                        CollOfChanges.Remove(pair.Value.Element);
                    Added = null;

                    Deleted = DicOfChanges.Where(x => (x.Value).Modification == CollStat.Deleted);
                    foreach (KeyValuePair<int, _ElementKeeper<T>> pair in Deleted)
                        CollOfChanges.Remove(pair.Value.Element);
                    Deleted = null;

                    var Modified = DicOfChanges.Where(x => (x.Value).Modification == CollStat.Replacer);
                    foreach (KeyValuePair<int, _ElementKeeper<T>> pair in Modified)
                        CollOfChanges.Remove(pair.Value.Element);
                    Modified = null;
                    break;

                default:
                    break;
            }

            return CollOfChanges;
        }

        /// <summary>
        /// Creats a ObservableCollection that contains all Elements from the overhanded CollStat Type
        /// </summary>
        /// <param name="stat">CollStat Type</param>
        /// <returns>ObservableCollection</returns>
        private ObservableCollection<T> CollOfStat(CollStat stat)
        {
            var Coll =new ObservableCollection<T>();
            var Modified = DicOfChanges.Where(x => (x.Value).Modification == stat);

            //Hinzufügen dieser Elemente
            foreach (KeyValuePair<int, _ElementKeeper<T>> pair in Modified)
                Coll.Add(pair.Value.Element);

            return Coll;
        }
    }
}

i still think there is to much Linq. Any suggestion to improvement the performance would be greatly appreciated

EDIT 2:

i found a solution here it contains more that i want but still a better solution than mine :D

Was it helpful?

Solution

You just need to subscribe to the CollectionChanged event of ObservableCollection and then check the value of the Action property of the NotifyCollectionChangedEventArgs

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top