CollectionChangedEventManager不转发自定义集合的事件

时间:2015-03-26 02:24:39

标签: c# observablecollection weak-events

我有一个自定义INotifyCollectionChanged类,它基本上只包含标准ObservableCollection。每当添加/删除某些内容时,CollectionChanged事件都会按预期引发。但是,当我尝试使用WeakEventListener侦听此事件时,侦听器永远不会收到该事件。为什么会发生这种情况?如何解决这个问题?

在下面的示例中,我希望抛出NotImplementedException,但测试用例成功(这清楚地表明事件真的被提升)。如果您将集合更改为ObservableCollection而不是Wrapper,则会按预期抛出异常。

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

可能相关但仍然没有答案:
Why WeakEventManager does not fire an event when the sender is not the nominal?

1 个答案:

答案 0 :(得分:1)

至于原因,问题与this question中的问题相同。从本质上讲,在事件管理器中注册的源必须与事件的发送者相同。

作为此限制的解决方法,我只需要确保Wrapper发送事件,而不是直接在包装集合上使用事件。

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