【问题标题】:How to provide a "List" of removed/original Items for ICollection Childs如何为 ICollection Childs 提供已删除/原始项目的“列表”
【发布时间】:2013-01-30 15:47:06
【问题描述】:

嗨,我想做SomeCollection.GetChanges(ItemState.Deleted) 之类的事情,结果应该是所有已删除的项目

你可以用DataTable 做这样的事情。 但是如何在List<T>ObservableCollection<T> 中实现这一点?

是否已经有解决此问题的方法? 如果没有,创建这样的 Collection 是否明智?

非常感谢任何建议

编辑:

到目前为止,这是我的代码,我现在已经测试并修复了它,但我仍然认为可能有更好的解决方案

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;
        }
    }
}

我还是觉得 Linq 太多了。任何改进性能的建议将不胜感激

编辑 2:

我找到了一个解决方案 here 它包含我想要的更多但仍然比我更好的解决方案:D

【问题讨论】:

  • 到目前为止你有没有尝试过?
  • 否,仅适用于 DataTable 和 WF。现在我将 WPF 与 MVVM 和 Lists 以及其他 MVVM 的东西一起使用,所以不想为此使用 DataTables
  • @DavidL 现在我绑定了一些东西,看看我的编辑,但它看起来并不高效

标签: c# list datatable observablecollection icollection


【解决方案1】:

您只需要订阅 ObservableCollection 的CollectionChanged 事件,然后检查NotifyCollectionChangedEventArgsAction 属性的值

【讨论】:

  • 我知道 CollectionChanged 但我在删除它时不需要它。假设我有一个用户界面,用户可以在其中进行一些更改,然后他点击保存->现在我将使用他的更改执行一些逻辑,例如从数据库中删除/更新/..
  • @WiiMaxx 与其从集合中删除它,不如在要从集合中删除的类上设置一个标志 bool 属性。然后,当您去更新数据库时,您可以通过 IsDeleted 属性过滤掉
  • @DavidL 如果我已经将它从集合中删除了怎么办?如果我有一个包含许多元素的集合,Linq 会很慢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
  • 2021-11-29
  • 2015-01-03
  • 1970-01-01
相关资源
最近更新 更多