简体   繁体   中英

Static ObservableCollection Event is not firing

I have the following static ObservableCollection that gets updated using linq . Why the event is not firing ?

public static class myViewModel
{

    private static ObservableCollection<ObjA> CollectionA = new ObservableCollection<ObjA>();
    private static ObservableCollection<ObjB> CollectionB = new ObservableCollection<ObjB>();

    static myViewModel()
    {
        CollectionA.CollectionChanged += new NotifyCollectionChangedEventHandler(myHandler);
        CollectionA = new ObservableCollection(CollectionB.Select(abc=> new ObjA(abc, True));
    }

    private static void myHandler(object sender, NotifyCollectionChangedEventArgs e)
    {  
        //To do
        throw new NotImplementedException();
    }

    private static void updateCollection()
    {

        foreach (var x in CollectionA)
        {
            CollectionA.field=5;
        }
    }
}

Step one: Give CollectionA an event handler.

CollectionA.CollectionChanged += new NotifyCollectionChangedEventHandler(myHandler);

Step Two: Discard CollectionA and replace it with a different collection that has no handler.

CollectionA = new ObservableCollection(CollectionB.Select(abc=> new ObjA(abc, true));

See what you did there?

CollectionA returns a reference to a collection object. You aren't adding items to that collection object. You are replacing that collection object with a different collection object.

Add the items to the existing collection instead:

CollectionA.CollectionChanged += new NotifyCollectionChangedEventHandler(myHandler);

foreach (var x in CollectionB.Select(abc=> new ObjA(abc, true)))
{
    CollectionA.Add(x);
}

If you really want to replace the collection all at once, you need to add the handler to the new collection:

CollectionA = new ObservableCollection(CollectionB.Select(abc=> new ObjA(abc, true));

CollectionA.CollectionChanged += myHandler;

If myHandler has the correct parameters and return type, you don't need new NotifyCollectionChangedEventHandler .

The usual way to handle this type of thing is to make CollectionA a property which adds the handler itself:

private static ObservableCollection<ObjA> _collectionA;
public static ObservableCollection<ObjA> CollectionA {
    get { return _collectionA; }
    set {
        if (_collectionA != value)
        {
            //  Remove handler from old collection, if any
            if (_collectionA != null)
            {
                _collectionA.CollectionChanged -= myHandler;
            }

            _collectionA = value;

            if (_collectionA != null)
            {
                _collectionA.CollectionChanged += myHandler;

                //  Whatever myHandler does on new items, you probably want to do 
                //  that here for each item in the new collection. 
            }
        }
    }
}

static myViewModel()
{
    //  Now, whenever you replace CollectionA, the setter will add the changed 
    //  handler automatically and you don't have to think about it. 
    CollectionA = new ObservableCollection(CollectionB.Select(abc=> new(abc, True));
}

Update

Now, what what are we doing with the items? Maybe we want to know when their properties change. ObservableCollection won't do that for us, but we can wire it up ourselves.

It's fun to think about ways to refactor this code in a more conveniently reusable way.

private static ObservableCollection<ObjA> _collectionA;
public static ObservableCollection<ObjA> CollectionA
{
    get { return _collectionA; }
    set
    {
        if (_collectionA != value)
        {
            //  Remove handler from old collection, if any
            if (_collectionA != null)
            {
                _collectionA.CollectionChanged -= myHandler;
            }

            //  1. Remove property changed handlers from old collection items (if old collection not null) 
            //  2. Add property changed to new collection items (if new collection not null) 
            AddAndRemovePropertyChangedHandlers(_collectionA, value, ObjA_PropertyChanged);

            _collectionA = value;

            if (_collectionA != null)
            {
                _collectionA.CollectionChanged += myHandler;
            }
        }
    }
}

//  NotifyCollectionChangedEventArgs gives us non-generic IList rather than IEnumerable
//  but all we're doing is foreach, so make it as general as possible. 
protected static void AddAndRemovePropertyChangedHandlers(
    System.Collections.IEnumerable oldItems, 
    System.Collections.IEnumerable newItems, 
    PropertyChangedEventHandler handler)
{
    if (oldItems != null)
    {
        //  Some items may not implement INotifyPropertyChanged. 
        foreach (INotifyPropertyChanged oldItem in oldItems.Cast<Object>()
            .Where(item => item is INotifyPropertyChanged))
        {
            oldItem.PropertyChanged -= handler;
        }
    }

    if (newItems != null)
    {
        foreach (INotifyPropertyChanged newItem in newItems.Cast<Object>()
            .Where(item => item is INotifyPropertyChanged))
        {
            newItem.PropertyChanged += handler;
        }
    }
}

private static void ObjA_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
}

private static void myHandler(object sender, 
    System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    //  If e.Action is Reset, you don't get the items that were removed. Oh well. 
    AddAndRemovePropertyChangedHandlers(e.OldItems, e.NewItems, ObjA_PropertyChanged);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM