I have a class which has an
ObservableCollection<int>
as a property, and I'm trying to change a value inside that property of an instance of that class. Here's the code I have and that's getting a TargetException:
object[] index = null;
var originalPropertyName = propertyName;
if (propertyName.Contains("[") && propertyName.Contains("]"))
{
index = new object[1];
index[0] = Convert.ToInt32(propertyName.Split('[')[1].Split(']')[0]);
propertyName = propertyName.Split('[')[0];
}
PropertyInfo pi = item.GetType().GetProperty(propertyName);
PropertyInfo opi = item.GetType().GetProperty(originalPropertyName);
Type pType = index != null ? pi.PropertyType.GetGenericArguments()[0] : pi.PropertyType;
if (pi != null)
{
object convertedValue = Convert.ChangeType(value, pType);
if (index == null)
{
item.GetType().GetProperty(propertyName).SetValue(item, convertedValue, null);
}
else
{
//PropertyInfo ipi = pi.PropertyType.GetProperties().Single(p => p.GetIndexParameters().Length > 0);
//var collection = pi.GetValue(item, index);
//collection.GetType().GetProperty("Value").SetValue(collection, convertedValue, null);
var _pi = pi.PropertyType.GetProperty("Item");
_pi.SetValue(pi, convertedValue, index);
}
}
How propertyName is obtained isn't shown above, but in the case of an indexed property, it begins its life as "IndexedProperty[10]" for example.
In the comments after that "else" you can see other things I've tried, by reading some other stackoverflow posts and on other forums on how to do this, but I've failed so far. Any ideas?
Casting the property to ObservableCollection isn't feasible, because I want this to be dynamic.
The concept of the whole thing is to have a DataGrid that's data-bound and have paste work correctly by updating the proper properties of each instance, no matter if the properties are indexed or not. Non-indexed properties work fine, but I can't get the ObservableCollection ones to work.
SetValue(Object, Object, Object[]) Sets the property value of a specified object with optional index values for index properties.
To set property values via Reflection, you must use the Type. GetProperty() method, then invoke the PropertyInfo. SetValue() method. The default overload that we used accepts the object in which to set the property value, the value itself, and an object array, which in our example is null.
Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties.
A class with an ObservableCollection<int>
as a property doesn't actually have an indexed property in the traditional sense of an indexer. It just has a non-indexed property which itself has an indexer. So you need to use GetValue
to start with (without specifying an index) and then fetch the indexer on the result.
Basically, you need to remember that:
foo.People[10] = new Person();
is equivalent to:
var people = foo.People; // Getter
people[10] = new Person(); // Indexed setter
It looks like you were nearly there with this commented out code:
//var collection = pi.GetValue(item, index);
//collection.GetType().GetProperty("Value").SetValue(collection, convertedValue, null);
... but you were applying the index at the wrong point. You want (I think - the question isn't terribly clear):
var collection = pi.GetValue(item, null);
collection.GetType()
.GetProperty("Item") // Item is the normal name for an indexer
.SetValue(collection, convertedValue, index);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With