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

前端 未结 20 1633
不知归路
不知归路 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 01:04

    For the scenario of attaching and detaching event handlers to the elements of the ObservableCollection there is also a "client-side" solution. In the event handling code you can check if the sender is in the ObservableCollection using the Contains method. Pro: you can work with any existing ObservableCollection. Cons: the Contains method runs with O(n) where n is the number of elements in the ObservableCollection. So this is a solution for small ObservableCollections.

    Another "client-side" solution is to use an event handler in the middle. Just register all events to the event handler in the middle. This event handler in turn notifies the real event handler trough a callback or an event. If a Reset action occurs remove the callback or event create a new event handler in the middle and forget about the old one. This approach also works for big ObservableCollections. I used this for the PropertyChanged event (see code below).

        /// <summary>
        /// Helper class that allows to "detach" all current Eventhandlers by setting
        /// DelegateHandler to null.
        /// </summary>
        public class PropertyChangedDelegator
        {
            /// <summary>
            /// Callback to the real event handling code.
            /// </summary>
            public PropertyChangedEventHandler DelegateHandler;
            /// <summary>
            /// Eventhandler that is registered by the elements.
            /// </summary>
            /// <param name="sender">the element that has been changed.</param>
            /// <param name="e">the event arguments</param>
            public void PropertyChangedHandler(Object sender, PropertyChangedEventArgs e)
            {
                if (DelegateHandler != null)
                {
                    DelegateHandler(sender, e);
                }
                else
                {
                    INotifyPropertyChanged s = sender as INotifyPropertyChanged;
                    if (s != null)
                        s.PropertyChanged -= PropertyChangedHandler;
                }   
            }
        }
    
    0 讨论(0)
  • 2020-11-30 01:04

    This is a hot subject ... because in my opinion, Microsoft did not do its job properly ... yet again. Don't misunderstand me, I like Microsoft, but they are not perfect!

    I read most of the previous comments. I agree with all those who think that Microsoft did not programmed Clear() properly.

    In my opinion, at least, it needs an argument to make it possible to detach objects from an event ... but I also understand the impact of it. Then, I thought up this proposed solution.

    I hope it will make everybody happy, or at least, most everyone ...

    Eric

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Reflection;
    
    namespace WpfUtil.Collections
    {
        public static class ObservableCollectionExtension
        {
            public static void RemoveAllOneByOne<T>(this ObservableCollection<T> obsColl)
            {
                foreach (T item in obsColl)
                {
                    while (obsColl.Count > 0)
                    {
                        obsColl.RemoveAt(0);
                    }
                }
            }
    
            public static void RemoveAll<T>(this ObservableCollection<T> obsColl)
            {
                if (obsColl.Count > 0)
                {
                    List<T> removedItems = new List<T>(obsColl);
                    obsColl.Clear();
    
                    NotifyCollectionChangedEventArgs e =
                        new NotifyCollectionChangedEventArgs
                        (
                            NotifyCollectionChangedAction.Remove,
                            removedItems
                        );
                    var eventInfo =
                        obsColl.GetType().GetField
                        (
                            "CollectionChanged",
                            BindingFlags.Instance | BindingFlags.NonPublic
                        );
                    if (eventInfo != null)
                    {
                        var eventMember = eventInfo.GetValue(obsColl);
                        // note: if eventMember is null
                        // nobody registered to the event, you can't call it.
                        if (eventMember != null)
                            eventMember.GetType().GetMethod("Invoke").
                                Invoke(eventMember, new object[] { obsColl, e });
                    }
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题