user3521178 user3521178 - 3 months ago 56
C# Question

NotifyCollectionChangedEventArgs Item Inaccessible

I have a handler for an

ObservableCollection
CollectionChanged
event and for the life of me cannot boil down the
NotifyCollectionChangedEventArgs
to the item contained within the
IList
. New items added to the collection are in the
.NewItems
IList. 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.

Answer

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.