在不使用ObservableCollection的情况下在List上抛出PropertyChanged - 它可以完成吗?

时间:2014-03-13 18:55:54

标签: c# list events

我有一个扩展IList<T>的类,我希望附加一些事件,当列表中的项目发生变化时会触发这些事件。


注意:我不能使用ObservableCollection。我不能使用ObservableCollection,因为我只能使用.NET 3.X而不能使用WindowsBase。如您所知,ObservableCollection在.NET 3.X中的WindowsBase中实现。


我的问题很简单:有没有办法在IList中的元素发生变化时触发事件?

编辑:我应该提到T确实实现了INotifyPropertyChanged

1 个答案:

答案 0 :(得分:1)

我创建了一个ObservableList,通知您项目是否已添加,删除,替换以及项目本身是否已更改。项目类型必须实现INotifyPropertyChanged

public class ObservableList<T> : IList<T>, IDisposable
    where T : INotifyPropertyChanged
{
    List<T> _innerList;
    bool _disposed;

    #region Notification

    public enum Action
    {
        Add,
        Remove,
        Replace,
        ItemPropertyChanged
    }

    public class ListOrItemChangedEventArgs : EventArgs
    {
        public ListOrItemChangedEventArgs(IList<T> oldItems, IList<T> newItems, int startingIndex, Action action, string propertyName)
        {
            StartingIndex = startingIndex;
            Action = action;
            OldItems = oldItems;
            NewItems = newItems;
        }

        public Action Action { get; private set; }

        public IList<T> OldItems { get; private set; }
        public IList<T> NewItems { get; private set; }

        public int StartingIndex { get; private set; }

        public string PropertyName { get; private set; }
    }

    public delegate void ListOrItemChangedEventHandler(ObservableList<T> sender, ListOrItemChangedEventArgs e);

    public event ListOrItemChangedEventHandler ListOrItemChanged;

    private void OnListOrItemChanged(IList<T> oldItems, IList<T> newItems, int startingIndex, Action action, string propertyName)
    {
        var eh = ListOrItemChanged;
        if (eh != null) {
            eh(this, new ListOrItemChangedEventArgs(oldItems, newItems, startingIndex, action, propertyName));
        }
    }

    void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        T item = (T)sender;
        OnListOrItemChanged(new List<T>(1) { item }, new List<T>(1) { item }, _innerList.IndexOf(item), Action.ItemPropertyChanged, e.PropertyName);
    }

    #endregion

    public ObservableList()
    {
        _innerList = new List<T>();
    }

    public ObservableList(int capacity)
    {
        _innerList = new List<T>(capacity);
    }

    public ObservableList(IEnumerable<T> items)
    {
        var coll = items as ICollection;
        if (coll == null) {
            _innerList = new List<T>();
        } else {
            _innerList = new List<T>(coll.Count);
        }
        foreach (T item in items) {
            _innerList.Add(item);
            if (item != null) {
                item.PropertyChanged += Item_PropertyChanged;
            }
        }
    }

    public void AddRange(IEnumerable<T> items)
    {
        int startIndex = _innerList.Count;
        _innerList.AddRange(items);
        foreach (T item in items) {
            if (item != null) {
                item.PropertyChanged += Item_PropertyChanged;
            }
        }
        OnListOrItemChanged(null, new List<T>(items), startIndex, Action.Add, null);
    }

    #region IList<T> Members

    public int IndexOf(T item)
    {
        return _innerList.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        _innerList.Insert(index, item);
        if (item != null) {
            item.PropertyChanged += Item_PropertyChanged;
        }
        OnListOrItemChanged(null, new List<T>(1) { item }, index, Action.Add, null);
    }

    public void RemoveAt(int index)
    {
        T item = _innerList[index];
        _innerList.RemoveAt(index);
        if (item != null) {
            item.PropertyChanged -= Item_PropertyChanged;
        }
        OnListOrItemChanged(new List<T>(1) { item }, null, index, Action.Remove, null);
    }

    public T this[int index]
    {
        get { return _innerList[index]; }
        set
        {
            T oldItem = _innerList[index];
            if (oldItem != null) {
                oldItem.PropertyChanged -= Item_PropertyChanged;
            }

            _innerList[index] = value;

            if (value != null) {
                value.PropertyChanged += Item_PropertyChanged;
            }
            OnListOrItemChanged(new List<T>(1) { oldItem }, new List<T>(1) { value }, index, Action.Replace, null);
        }
    }

    #endregion

    #region ICollection<T> Members

    public void Add(T item)
    {
        int startIndex = _innerList.Count;
        _innerList.Add(item);
        if (item != null) {
            item.PropertyChanged += Item_PropertyChanged;
        }
        OnListOrItemChanged(null, new List<T>(1) { item }, startIndex, Action.Add, null);
    }

    public void Clear()
    {
        foreach (T item in _innerList) {
            if (item != null) {
                item.PropertyChanged -= Item_PropertyChanged;
            }
        }
        var oldItems = _innerList;
        _innerList = new List<T>();
        OnListOrItemChanged(oldItems, null, 0, Action.Remove, null);
    }

    public bool Contains(T item)
    {
        return _innerList.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _innerList.CopyTo(array, arrayIndex);
    }

    public int Count { get { return _innerList.Count; } }

    public bool IsReadOnly { get { return false; } }

    public bool Remove(T item)
    {
        int i = _innerList.IndexOf(item);
        if (i == -1) {
            return false;
        }
        item = _innerList[i]; // In case another instance is returned.
        if (item != null) {
            item.PropertyChanged -= Item_PropertyChanged;
        }
        _innerList.RemoveAt(i);
        OnListOrItemChanged(new List<T>(1) { item }, null, i, Action.Remove, null);
        return true;
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return _innerList.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _innerList.GetEnumerator();
    }

    #endregion

    #region IDisposable Members

    /// <summary>
    /// Removes PropertyChanged event handlers from all the items.
    /// </summary>
    public void Dispose()
    {
        if (!_disposed) {
            _disposed = true;
            foreach (T item in _innerList) {
                if (item != null) {
                    item.PropertyChanged -= Item_PropertyChanged;
                }
            }
        }
    }

    #endregion
}