简体   繁体   中英

CollectionChangedEventManager not forwarding event for custom collection

I have a custom INotifyCollectionChanged class, which essentially just wraps around the standard ObservableCollection . Whenever something is added/removed, the CollectionChanged event is raised as expected. However, when I try to listen to this event using a WeakEventListener , the listener never receives the event. Why is this happening and how do I fix this?

In below sample, I'd expect a NotImplementedException to be thrown, but the test case succeeds (which clearly indicates that the event is truly raised). If you change the collection to be an ObservableCollection instead of a Wrapper , the exception does get thrown as expected.

public class Test : IWeakEventListener
{
    private class Wrapper : INotifyCollectionChanged
    {
        private readonly ObservableCollection<string> _internal 
                                     = new ObservableCollection<string>();

        public void Add(string s)
        {
            _internal.Add(s);
        }

        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add { _internal.CollectionChanged += value; }
            remove { _internal.CollectionChanged -= value; }
        }
    }

    public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }

    [Test]
    public void CustomCollectionTest()
    {
        //change to new ObservableCollection<string>() and the exception gets thrown
        var collection = new Wrapper(); 
        var raised = false;
        collection.CollectionChanged += (o, e) => raised = true;
        CollectionChangedEventManager.AddListener(collection, this);
        collection.Add("foobar");
        Assert.True(raised);
    }
}

Possibly related but still unanswered:
Why WeakEventManager does not fire an event when the sender is not the nominal?

As to why, the issue is the same as in this question . Essentially, the source registered with the event manager has to be the same as the sender of the event.

As a workaround for this limitation, I just have to make sure that the Wrapper sends the event, rather than directly using the event on the wrapped collection.

private class Wrapper : INotifyCollectionChanged
{
    private readonly ObservableCollection<string> _internal 
                                 = new ObservableCollection<string>();

    public Wrapper()
    {
        _internal.CollectionChanged += OnInternalChanged;
    }

    public void Add(string s)
    {
        _internal.Add(s);
    }

    private void OnInternalChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        var toRaise = CollectionChanged;
        if (toRaise != null)
            toRaise(this, e);
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;
}

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