Background
User controls in ASP.Net provide great opportunities for reuse on a web site. A user control is very similar to an ASP.Net page with a user interface and associated code behind file (optional). The difference is that the user control can be included on other pages. One very common example of a user control is a common header for pages on a web site. The header can be created once and simply placed on each page. User controls become more powerful by using information from the containing page to customize their display or behavior.
This article explores various techniques used to allow user controls or standalone classes to use properties or methods provided by containing web pages.
User Control Properties
The most common approach to sharing information between the page and the user controls it includes is to use properties on the user control.
WebUserControl1.ascx.cs
Created a simple user control that just contains a single label, provides a property DisplayText to set the label text.
public abstract class WebUserControl1 : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.Label Label1;
public string DisplayText
{
set
{
Label1.Text = value;
}
}
private void Page_Load(object sender, System.EventArgs e)
{
}
}
WebForm1.aspx
A sample web page that includes the user control, uses the property name as an attribute of the user control element. This works well for properties that are simple (not objects), and is consistent with how developers set properties on other controls (asp:textBox, etc).
<uc1:WebUserControl1 id=WebUserControl11 DisplayText="Hello World!" runat="server"></uc1:WebUserControl1>
WebForm2.aspx.cs
An alternative approach that is often used when the property is an object, is to set the property value in the code behind for the page. The trick involved with using this technique is that the user control must be defined in the code behind file for the page, and it must be accessible to the front end. When a project is built for ASP.Net, the code behind files are compiled and placed in an assembly in the "bin" folder for the project. The front end pages (.aspx) are compiled the first time they are requested on the web server. The page is complied into a class which derives from the class defined in the code behind file. The user control has an "id" property defined in the .aspx page, this must match the name of the defined variable in the code behind file for the instances to be the same. The safest way to define it is to use the "protected" access modifier which allows derived classes to access the variable, but not other classes. Leaving off the access modifier defaults to "private", which will lead to the infamous "Object Reference Not Set..." exception (the one defined in the code behind never gets instantiated).
public class WebForm2 : System.Web.UI.Page
{
protected WebUserControl1 WebUserControl11;
private void Page_Load(object sender, System.EventArgs e)
{
WebUserControl11.DisplayText = "Set from Code Behind";
}
}
Specific Parent Page
There are times when a user control is used
only on a specific page (often done to simplify an otherwise large page by breaking it down into user controls), and it may need to access properties or methods on that page. Every user control has a property "Page" that references the page on which the control is included. The Page property is of type System.Web.UI.Page, but the enclosing page is actually an instance of a particular class that derives from System.Web.UI.Page. Since the user control now casts to a specific page class type, this control will not work on any other pages!
SpecificPage.aspx.cs
This page includes a single label and a user control, a property on the page called "DisplayText" sets the label value. The class created for the code behind is named "SpecificPage".
public class SpecificPage : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label Label1;
public string DisplayText
{
set
{
Label1.Text = value;
}
}
private void Page_Load(object sender, System.EventArgs e)
{
}
}
SpecificPageControl.ascx.cs
The user control needs to cast the Page property to the class listed in the page code behind class in order to gain access to the property, because the property is only defined in that derived class, not its base class System.Web.UI.Page. The instance of the Page object is actually of the type "SpecificPage", but the Page property reference is of the type System.Web.UI.Page, so the cast is valid. Once the cast is complete, it is possible to access properties on that class, including the DisplayText property.
public abstract class SpecificPageControl : System.Web.UI.UserControl
{
private void Page_Load(object sender, System.EventArgs e)
{
((SpecificPage)Page).DisplayText = "Set page label";
}
}
Access Properties in the Base Page
Most ASP.Net sites should implement a
base page class that all pages on a site derive from. If the site uses this technique, some properties and methods may be exposed by the base page and can be accessed from a user control. Then the user controls can be used on all pages on the web site since they all derive from basePage.
basePage.cs
Example BasePage class overrides the OnInit to read a querystring value and stores in a local variable and provides a property to access it.
public class basePage :System.Web.UI.Page
{
public basePage()
{
}
private string code = "";
public string Code
{
get
{
return code;
}
}
override protected void OnInit(EventArgs e)
{
if (null != Request.QueryString["code"])
{
code = Request.QueryString["code"];
}
}
}
BasePageControl.ascx.cs
The user control simply casts now to the type of the basePage class, then it can access any properties defined on that class.
private void Page_Load(object sender, System.EventArgs e)
{
Label1.Text = ((basePage)Page).Code;
}
Interfaces
Sometimes a series of pages need to implement a consistent set of properties or methods without using inheritance. Since C# is limited to single inheritance, the use of interfaces is common. An interface is a contract, a class that claims to support an interface must implement the entire interface or a compile error occurs. Classes can only derive from a single class, but they can implement as many interfaces as they desire. An option for access page properties across a series of pages that do not derive from a common base class is to create an interface that contains the desired property. Each page that chooses to implement the given property implements the interface. A user control can then check if the page implements the given interface, and if so access the property.
helper.cs
This class defines the interface contract (without the implementation).
public class helper
{
public helper()
{
}
public interface ICode
{
string Code {get;}
}
}
InterfaceForm.aspx.cs
This class implements the interface.
public class InterfaceForm : System.Web.UI.Page, helper.ICode
{
public string Code
{
get
{
return "123";
}
}
private void Page_Load(object sender, System.EventArgs e)
{
}
}
InterfaceControl.ascx.cs
This uses the "is" operator which checks if the given object is the given type (or derives from the type). The check ensures that if a given page does not implement the interface, that control will not attempt to access the property.
private void Page_Load(object sender, System.EventArgs e)
{
if (Page is helper.ICode)
{
Label1.Text = ((helper.ICode)Page).Code;
}
}
Conclusion
There are many options for sharing information between a page and contained user controls. Which technique is used depends on the circumstances. Properties on the user control is the most common method, but it is sometimes necessary to use more advanced techniques.
Send comments or questions to robertb@aspalliance.com.