Reputation: 91
Here is my situation:
I have a 3rd party Component Control which I successfully inherited, and now I am doing some custumization to it.
Part of that customization, is to change the DefaultValues of some properties it has.
So far it all went OK, but this control has some "Sub" Classes in it, that I want to change their propeties' DefaultValues too.
By "Sub" Classes I mean: Let's say my control is called SomeControl, so it has properties in it, but it also has a property that is expandable, like: SomeControl.Rows, The .Rows property returns a RowCollection which has its own properties. So this is what I mean by "Sub" Class (please correct me if there's a better term for this)
In any case, If I want to change some DefaultValues in the RowCollection class, I need to inherit it too. The propblem is that RowCollection's Ctor is internal, so I cannot inherit that class.
So is there any other way for me to change the DefaultValue attribute for a property in a class that I cannot inherit?
Maybe via reflection?
I nee to change it for an instance(object) that I have existing - one instance, and not for the class in general.. (since after 1 object is created from it, no more are created..)
Thank you
Upvotes: 2
Views: 1328
Reputation: 13799
Summary: I don't think it is possible to do this via reflection, but here is how I would do it:
First get the property you want:
var defValAttr = typeof (SomeControl.RowCollection)
.GetProperty("yourProperty")
.GetCustomAttributes(typeof(DefaultValueAttribute), false)
.First()
as DefaultValueAttribute;
DefaultValueAttribute has a .Value property, which is readonly. To modify it you need reflection again to change the private .value field:
var valueField= typeof (DefaultValueAttribute)
.GetField("value", BindingFlags.NonPublic
| BindingFlags.GetField
| BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);
I have not tested this myself, but as far as I know this will not work. The objects returned by GetCustomAttributes are not the actual attributes; you can get the values of the real attributes this way, but you cannot change them. (see Can attributes be added dynamically in C#?)
However, even if this would work, it would change the DefaultValue for all instances of SomeControl.Rows, whether they are within your custom derived control or in the base control. There is no way to change only the DefaultValue of a single instance, since the this value is stored only once per class, not once per instance. It would be very wasteful if there was a copy of each attribute for each instance of an object.
So in conclusion, I don't think there is a way to do this.
As an alternative, you could decompile the third-party assembly and add your own assembly with InternalsVisibleTo, that way you can access the internal constructor.
Addendum: There may still be a way to do this, depending on what sort of attribute you want to change. The attributes accessible via reflection are as I said probably unchangeable. However The visual studio editor and the whole WPF component model actually uses a TypeDescriptor to manage attributes on top of the basic attribute system built into the language. You may be able to change the attributes used by the TypeProvider, and if code later accesses the attributes via TypeDescriptor, it may see the changed values.
The following is again untested:
var instanceOfRow = instanceOfYourControl.Rows;
var defValAttr = TypeDescriptor
.GetProperties(instanceOfRow)["yourProperty"]
.Attributes[typeof (DefaultValueAttribute)]
as DefaultValueAttribute;
var valueField= typeof (DefaultValueAttribute)
.GetField("value", BindingFlags.NonPublic
| BindingFlags.GetField
| BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);
Upvotes: 2