CollectionChangedEventManager not forwarding event for custom collection

1k Views Asked by At

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?

1

There are 1 best solutions below

0
On BEST ANSWER

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;
}