开发者

Why am I getting a NullReferenceException when trying to subclass from an ObservableCollection or BindingList?

开发者 https://www.devze.com 2023-03-27 00:52 出处:网络
I\'m using ObservableCollections as the ItemsSource for some of my bindings, and have run into a scenario where I would like to call OnCollectionChanged manually to notify that the list should be re-c

I'm using ObservableCollections as the ItemsSource for some of my bindings, and have run into a scenario where I would like to call OnCollectionChanged manually to notify that the list should be re-checked by the binding engine. (The BindingList analogue is OnListChanged).

Here's where the trouble begins. Maddeningly, these methods are protected and can't be called without subclassing these types. Ironpython supports this, but when I attempt to subclass, it fails spectacularly - even when I don't specify any overriding methods:

>>> class ObservableCollectionEx(System.Collections.ObjectModel.ObservableCollection):
...     pass
... 
Traceback (most recent call last):
  File "<string>", line 1, in <module>
SystemError: Object reference not set to an instance of an object.

>>> class BindingListEx(System.ComponentModel.BindingList):
...     pass
... 
开发者_StackOverflow社区Traceback (most recent call last):
  File "<string>", line 1, in <module>
SystemError: Object reference not set to an instance of an object.

I'm about to give up, and all I wanted to do was make one friggin' call to OnCollectionChanged! Help!


Sub-classing both ObservableCollection<T> and BindingList<T> are supported operations. Here's a sample I wrote for BindingList<T> which exposes OnListChanged and doesn't throw any exceptions

class BindingListEx<T> : BindingList<T>
{
    public void ForceListChanged()
    {
        base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
    }
}


class Program
{
    static void Main(string[] args)
    {
        var list = new BindingListEx<int>();
        list.Add(42);
        list.ForceListChanged();
    }
}


After doing some more research I've found a workaround. Reading this article on inheriting from generic classes sheds some light on what is going on behind the scenes, most notably this explanation:

Closed Construct generic is the term used to refer a scenario where a sub-class is non-generic and the base class is parameterized as concrete type.

public class SubClass : BaseClass<int>   {...}

Open Construct generic is the term used to refer a scenario where both the base and sub-class is parameterized as generic type.

public class SubClass<T> : BaseClass<T> {...}

According to this, what I'm trying to do in my original post (inheriting from ObservableCollections and BindingLists) is of the second form; trying to keep both the base and sub-class parameterized. While I still think this has to be possible in some way in IronPython, I can't figure out the syntax to do it, so I'll settle for the first form for now. And whaddaya know, it works:

>>> class BindingListEx(System.ComponentModel.BindingList[str]):
...     pass
... 
>>> 
>>> b = BindingListEx()
>>> b
<BindingListEx object at 0x000000000000002C>
>>> b.Add(3)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: expected str, got int
>>> b.Add("cow")
>>> 

So in this example, BindingListEx is non-generic, and subclasses from the BindingList parameterized base class that has been fed str as its parameter. This works for now. If anyone figures out how to do Open Construct generic inheritance (that second form up there), feel free to post it here and you'll get the accepted answer, as that was my original goal. For now, this will have to do.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号