When Clearing an ObservableCollection, There are No Items in e.OldItems

前端 未结 20 1782
不知归路
不知归路 2020-11-30 00:27

I have something here that is really catching me off guard.

I have an ObservableCollection of T that is filled with items. I also have an event handler attached to t

20条回答
  •  借酒劲吻你
    2020-11-30 00:42

    I had the same issue, and this was my solution. It seems to work. Does anyone see any potential problems with this approach?

    // overriden so that we can call GetInvocationList
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
        if (collectionChanged != null)
        {
            lock (collectionChanged)
            {
                foreach (NotifyCollectionChangedEventHandler handler in collectionChanged.GetInvocationList())
                {
                    try
                    {
                        handler(this, e);
                    }
                    catch (NotSupportedException ex)
                    {
                        // this will occur if this collection is used as an ItemsControl.ItemsSource
                        if (ex.Message == "Range actions are not supported.")
                        {
                            handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                        }
                        else
                        {
                            throw ex;
                        }
                    }
                }
            }
        }
    }
    

    Here are some other useful methods in my class:

    public void SetItems(IEnumerable newItems)
    {
        Items.Clear();
        foreach (T newItem in newItems)
        {
            Items.Add(newItem);
        }
        NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
    
    public void AddRange(IEnumerable newItems)
    {
        int index = Count;
        foreach (T item in newItems)
        {
            Items.Add(item);
        }
        NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List(newItems), index);
        NotifyCollectionChanged(e);
    }
    
    public void RemoveRange(int startingIndex, int count)
    {
        IList oldItems = new List();
        for (int i = 0; i < count; i++)
        {
            oldItems.Add(Items[startingIndex]);
            Items.RemoveAt(startingIndex);
        }
        NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List(oldItems), startingIndex);
        NotifyCollectionChanged(e);
    }
    
    // this needs to be overridden to avoid raising a NotifyCollectionChangedEvent with NotifyCollectionChangedAction.Reset, which our other lists don't support
    new public void Clear()
    {
        RemoveRange(0, Count);
    }
    
    public void RemoveWhere(Func criterion)
    {
        List removedItems = null;
        int startingIndex = default(int);
        int contiguousCount = default(int);
        for (int i = 0; i < Count; i++)
        {
            T item = Items[i];
            if (criterion(item))
            {
                if (removedItems == null)
                {
                    removedItems = new List();
                    startingIndex = i;
                    contiguousCount = 0;
                }
                Items.RemoveAt(i);
                removedItems.Add(item);
                contiguousCount++;
            }
            else if (removedItems != null)
            {
                NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItems, startingIndex));
                removedItems = null;
                i = startingIndex;
            }
        }
        if (removedItems != null)
        {
            NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItems, startingIndex));
        }
    }
    
    private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        OnCollectionChanged(e);
    }
    

提交回复
热议问题