Help with Reflection and accessing controls on page
Hi all,
I am trying to access a couple of controls on a page via Reflection. More specifically, I am trying to get and set the value of a textbox using:
Dim
dispCompInfoAs System.Reflection.FieldInfo
dispCompInfo =Me.GetType.GetField("txtFirstName", Reflection.BindingFlags.NonPublic | Reflection.bindingflags.Instance)However, I cannot seem to get a return value from any of the Type's "Get..." methods. Can someone tell me what I am doing wrong?
Also, once I get the control, do I need to get it's "Text" property to get and set values in it, or is there another more convenient/clever way to do this?
Thanks in advance for any assistance!
Cheers,
Chris
Hi Chris,
Can you post the declaration of the txtFirstName field, so that I can try to figure out the combination of BindingFlags that you need?
Once you have the FieldInfo for the control, you can do something along these lines:
| |
Dim firstNameBox As TextBox firstNameTextBox = CType(dispCompInfo.GetValue(Me), TextBox) firstNameTextBox.Text = "Some new text"
|
(in C#)
| |
TextBox firstNameTextBox = dispCompInfo.GetValue(this) as TextBox; firstNameTextBox.Text = "Some new text"
|
-Shawn
Hi Shawn,
Thanks for the quick reply.
The declaration is straight from the designer generated code:
Protected
WithEvents txtFirstName As System.Web.UI.WebControls.TextBox
The problem you're running into is that the WithEvents keyword causes VB to mangle the name of a variable. Specifically, if you declare a field as WithEvents, VB will replace the field with one that has a leading underscore prefixed to it. It will also add a property to the class with the same name as the original field.
To get around this issue, you can just replace txtFirstName with _txtFirstName in your GetField call.
You can see the transformation if you run ildasm on the output assembly. You'll see something along these lines:
.field private class [System.Web]System.Web.UI.WebControls.TextBox _txtFirstName
.custom instance void [mscorlib]System.Runtime.CompilerServices.AccessedThroughPropertyAttribute::.ctor(string)
//
// ...
//
.property instance class [System.Web]System.Web.UI.WebControls.TextBox txtFirstName()
{
.get instance class [System.Web]System.Web.UI.WebControls.TextBox Test::get_txtFirstName()
.set instance void Test:: set_txtFirstName(class [System.Web]System.Web.UI.WebControls.TextBox)
}
-Shawn
Ok, Shawn, that makes perfect sense, however, I am getting an error on the assignment that the right side of the "=" is Nothing.
dispCompInfo =
Me.GetType.GetField("_" & methInfoPair.Second, Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance)methInfoPair.Second contains the string, "txtFirstName".
If I do a Me.GetType.GetFields, I get an empty collection. Me, BTW, is a subclass of System.Web.UI.UserControl, if that matters.
Cheers,
Chris
Right, if you take a look in the IL created from when VB is mangling your field, it's creating a private field and a protected property.
So, if you're in a subclass, you'll need to either reflect over the type that actually declares the txtFirstName WithEvents variable, or go after the property. To do that you'll need to use code similar to the following:
| |
Dim dispCompInfo As System.Reflection.PropertyInfo dispCompInfo = Me.GetType.GetProperty("txtFirstName", BindingFlags.NonPublic Or Reflection.bindingflags.Instance) Dim firstNameTextBox as TextBox firstNameTextBox = CType(dispCompInfo.GetValue(Me, Nothing), TextBox)
|
Ok... so perhaps this is poor coding practice, but we are not using properties for the controls on a web page at all. If the control is txtFirstName, then in the code we would say txtFirstName.Text = "Chris".
Is there any way to get at this thing given that circumstance?
Even though you're not using properties directly, the Visual Basic compiler is creating one for you. So, the transformation that's happening is:
txtFirstName (protected field) => _txtFirstName (private field) and txtFirstName (protected property)
And that's done for you by the compiler. So, even if you're not using properties directly, you'll still need to use the GetProperty code from my previous post in order to access the txtFirstName field.
Does that make sense?
That did it, and yes it did make sense! Thanks, Shawn!