Monday, 22 October 2007

Getting a hold of a user control in code behind

Issue

Unable to cast an object to a user control you have created.

Reason

The problem is normally because the Usercontrol is not in the web root directory. You can add the control without issue - and also call the methods and use it as normally. However if you get the usercontrol as an object then there is no way to cast it to anything (shown below)



Solution 1

Well, the easiest solution is to move the usercontrol to the web root directory, however this may not be possible to do for loads of reasons!

Solution 2

Add a namespace - if the user control has a name space then you can easily get a hold of the control and cast the object!

Solution 3

This is the best way I know of. All you need to do is add an interface, and then make the user control inherit from it. Now you can cast the object you have to this interface.

The interface:
interface IHasValue
{
decimal Value { get; }
}

The usercontrol:
using System;

public partial class UserControls_DecimalOnlyTextbox : System.Web.UI.UserControl, IHasValue
{
protected void Page_Load(object sender, EventArgs e)
{

}
public decimal Value
{
get
{
return 0;//Just a demo!
}
}
}
The page:
using System;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//This still works fine!
decimal dValue = DecimalOnlyTextbox1.Value;
//This can find the control ok
object oControl = Page.FindControl("DecimalOnlyTextbox1");
//Now we have something!
IHasValue ucValue = oControl as IHasValue;
if (ucValue != null)
{
decimal dCastedValue = ucValue.Value;
}
}
}
This can be used in loads of different scenarios , however there is one final solution (which does have a differant advantage!)

Solution 4

You can try and extract the value using reflection - this works, but I would always suggest avoiding relfection if at all possible.

The Page:
using System;
using System.Web.UI;
using System.Reflection;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//This still works fine!
decimal dValue = DecimalOnlyTextbox1.Value;
//This can find the control ok
object oDecimalControl = Page.FindControl("DecimalOnlyTextbox1");
//And this is a way to get the value using reflection
Type oType = oDecimalControl.GetType();
object oRes =oType.InvokeMember("Value", BindingFlags.Default | BindingFlags.GetProperty,
null,
oDecimalControl,
null);
decimal dValue4 = decimal.Parse(oRes.ToString());

}
}
As I said there is an advantage to using reflection. One final issue I haven't mentioned is if you want to dynamically add a usercontrol to a form. Solution 1, and Solution 2 will allow this easily - but Solution 3 (using an interface) does not. With a small tweak you can do this with this solution - however you need to be able to get a reference to the type of the usercontrol in order to instantiate it. This may mean hiding a usercontrol on the form just for the purpose of allowing you to create other ones dynamically. This should only be used as a last resort!!
using System;
using System.Web.UI;
using System.Reflection;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
object oDecimalControl = Page.FindControl("DecimalOnlyTextbox1");
//We need to get a hold of a referance to the control - cant create
//a new control without a copy of it.
Type oType = oDecimalControl.GetType();
//Now we have the type we can create an instance of it
object oNewObject = Activator.CreateInstance(oType);
//And this can be converted to a control
Control oNewControl = oNewObject as Control;
//Now this control can be added to the page
Page.Controls.Add(oNewControl);
}
}
If you for some crazy reason want to know more about reflection then take a look here

No comments: