Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NotifyCollectionChangedEventArgs Item Inaccessible

I have a handler for the CollectionChanged event of an ObservableCollection<T> object, and cannot figure out how to use the NotifyCollectionChangedEventArgs to retrieve the item contained within the IList for the event.

New items added to the collection are in the NewItems property, an IList object. Intellisense won't let me access .Item[Index] (which I should be able to according to the docs) nor can I cast the NewItems list to a local variable (according to debug the NewItems list is a System.Collections.ArrayList.ReadOnlyList which doesn't seem to exist as an accessible class in MSDN.)

What am I doing wrong?

Example:

private void ThisCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Item I = e.NewItems._________;//<<<<<cannot access any property to get the item
        var j = e.NewItems;//System.Collections.ArrayList.ReadOnlyList, see if you can find in the MSDN docs.
        IList I1 = (IList) e.NewItems;//Cast fails.
        IList<Item> = (IList<Item>)e.NewItems.________;//<<<<<<<Can't make this cast without an IList.Item[Index] accessor.
        var i = j[0]; //null
        var ioption = j.Item[0]; //no such accessor
        string s = (string)i; //null
    }

This example is keeping things as generic as possible and still fails.

like image 733
NWoodsman Avatar asked Aug 21 '16 18:08

NWoodsman


1 Answers

Without a good Minimal, Complete, and Verifiable code example it will be impossible to say exactly what you need to do. But in the meantime, let's try to clear up at least some of your misconceptions from the code you posted:

private void ThisCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    Item I = e.NewItems._________;//<<<<<cannot access any property to get the item
    var j = e.NewItems;//System.Collections.ArrayList.ReadOnlyList, see if you can find in the MSDN docs.
    IList I1 = (IList) e.NewItems;//Cast fails.
    IList<Item> = (IList<Item>)e.NewItems.________;//<<<<<<<Can't make this cast without an IList.Item[Index] accessor.
    var i = j[0]; //null
    var ioption = j.Item[0]; //no such accessor
    string s = (string)i; //null
}
  1. NotifyCollectionChangedEventArgs.NewItems is a property, with the type IList, a non-generic interface. The two key aspects of this interface as it relates to the NewItems property is that you can get the Count of items, and you can index the list. Indexing the list returns an object; it's up to you to cast that to an appropriate type.
  2. System.Collections.ArrayList.ReadOnlyList is a private class in the framework. You are not meant to use it directly. It's simply the implementation of IList that the NewItems property returns. The important thing about this implementation is that it's read-only. IList members like Add(), Insert(), and Remove() are not supported. All you can do is get items out. But just as important is that, as far as your code is concerned, the only type that's important is IList. You don't get to access members of private types directly; they are usable only through the public interfaces they implement.
  3. You are not specific about what you mean by "Cast fails". That it would is implausible, since the NewItems property is already of the type IList. A cast to IList would succeed trivially.
  4. It is true that you can't cast IList to the generic IList<Item>. The implementation of IList you're dealing with is the private class System.Collections.ArrayList.ReadOnlyList, which can't possibly implement the generic IList<Item> interface. After all, the ReadOnlyList was written by Microsoft and is in the .NET framework. How would they know about your Item type?
  5. You are not meant to use the Item property indexer of an object explicitly. This exists as a hidden member. Instead, you're expected to use the built-in C# syntax where you index off the object itself. I.e. e.NewItems[0] or j[0].
  6. Once you have assigned a null to the variable i, no amount of casting is going to change that null value into something else. Not string, not some other type.

You've tried a lot of different things, most of which make no sense so it's not a surprise they don't work. The closest you've gotten would be the j[0] expression. But you can just use e.NewItems directly. Your code should look more like this:

private void ThisCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // Assumes that the elements in your collection are in fact of type "Item"
    Item item = (Item)e.NewItems[0];

    // do something with "item"
}

However, it's important to note that you need to first check to see what kind of change has occurred to the collection. The NewItems list may be empty, if there aren't actually any new items. An element of the list may be null, if the newly set item value was in fact null. Whether you can successfully cast a non-null element value to Item depends on what Item actually is here, and whether your collection would ever actually have an element of that type in it. Likewise your attempts to cast to string. If the list doesn't contain elements of type string, then casting any non-null element value to string isn't going to work.

But these are all issues that are specific to the rest of the code. You haven't provided that, so the best I can do is try to explain in general terms all of the ways you seem to current misunderstand how this event and its supporting types work.

like image 99
Peter Duniho Avatar answered Oct 14 '22 13:10

Peter Duniho