User Controls
ASP.NET Makes Reusing Code Easy
October 30, 2009
asp:feature
Languages: VB
Technologies: User Controls | Code-behind | Reflection
UserControls
ASP.NETMakes Reusing Code Easy
By Doug Seven
ASP.NETand the .NET Framework introduce a new structure for building dynamic Webapplications. In previous incarnations of ASP, developers became accustomed toworking with server-side includes as a means of easy code reuse. They were thebest thing available at the time, but using includes still came with problems:
Includeswere processed in the same space as the page they were on, so variableconflicts were frequent.
Aninclude file could be used only once on a page, so making controls thatappeared multiple times on a page was cumbersome.
Includesdid not support an object model that allowed for exposing properties andmethods.
AlthoughASP.NET does support the use of includes, it also introduces a new means ofencapsulating code for reuse: the user control.
In thisarticle, you will learn what a user control is, what its advantages are, andhow to build and interact with it. You ll start with some basic examples andbuild on them until you have made a complex user control that exposesproperties and methods.
What Is a User Control?
The .NETFramework SDK documentation defines a user control as a user-authored servercontrol that enables an ASP.NET page to be reused as a server control. A fewmodifications can turn any ASP.NET Web Form into a user control you ll learnmore about that later. For now, understand that in its simplest form, a usercontrol is no more than text saved in a separate file and used on a Web Formlike any server control.
Usercontrols provide an easy means of writing reusable logic and user-interfacecode. You can write user controls in any text editor, as you can Web Forms.However, you must save user controls with the extension .ascx. The .NETFramework identifies them as user controls based on this extension. Usercontrols are compiled the first time they are used and are saved in memory thesame way Web Forms are. One of the great advantages user controls have overincludes is that user controls support the ASP.NET object model, which meansthey can expose properties and methods like any other object in the .NETFramework. User controls are designed for use in a single Web application, andare not designed to port across application boundaries. For reusable componentsthat encapsulate logic and UI and are for use in multiple applications, usecustom server controls.
Building a Basic User Control
As Isaid before, a user control is, in its simplest form, just text saved in aseparate file that you can use on any Web Form in your application. You cannotnavigate to user controls independently because they are only accessible ascontrols on a Web Form. Because of this, user controls should never contain , , and elements. Those elementswill be in the Web Form.
To builda simple user control, open your favorite text editor and create a new filenamed MyUserControl.ascx. In this file, type the text Thisis my user control andsave the file. That s it. You have created a user control. To use it, registerit on a Web Form, which will enable you to place it on the Web Form just likeany ASP.NET server control. Create a new Web Form named WebForm1.aspx in thesame directory as the user control and add the code from FIGURE 1.
<%@ RegisterTagPrefix="DotNetJunkies"
TagName="MyUserControl"
Src="MyUserControl.ascx" %>
FIGURE 1:Registering a user control on a Web Form.
Withthis code, you register the user control on the Web Form using the @Register directive. The three attributes of the @ Register directiveare:
TagPrefix The prefix used when placing thecontrol on the Web Form, similar to how asp is used to prefix intrinsicserver controls.
TagName The name by which the control isreferenced.
Src The absolute or relativelocation of the user control.
When youwant to place the user control on the page, use the syntax .The .NET Framework locates the user control based on the Src attribute, and Just-In-Time (JIT) compiles it and renders theuser control on the page.
Exposing Properties
As withany object in the .NET Framework, user controls can expose properties. Once auser control exposes a property, you can access it either declaratively orprogrammatically. Creating properties for a user control is the same ascreating properties for any object. Properties can be created as Public instances of a variable, or as Property objects with Get and Set methods.
Changethe MyUserControl.aspx file to include the following code:
Public Text AsString
<%=Text%>
Withthis code, you create a public string variable named Text. This variableis accessible outside the user control because you declared it publicly. Thecode uses the <%= %> Response.Write shortcut to write the value ofthe Text variable. In the Web Form, you can set the value of the Text variable declaratively, asfollows:
Text="This is the Textproperty." /> The resulting page is shown in FIGURE 2.
FIGURE 2: The user control isrendered as an HTML element within the page. One ofthe advantages user controls have over include files is that user controls areprocessed in their own sandboxes. In other words, each instance of a usercontrol is in an isolated processing space, which protects it from any variableconflicts. This enables multiple instances of the same user control on one WebForm, without any conflicts. Change WebForm1.aspx to use the code from FIGURE3. <%@ RegisterTagPrefix="DotNetJunkies" TagName="MyUserControl" SRC="MyUserControl.ascx" %>
Text="This is the first usercontrol." />
Text="This is the second usercontrol." />
Text="This is the third usercontrol." /> FIGURE 3:Using multiple instances of one user control. In thisWeb Form, you use the same user control three times and provide a separatevalue for the Text property witheach one. If you had tried to use the same include file three times in one ASPpage, you would have raised the following error: MicrosoftVBScript compilation (0x800A0411) Name redefined. Becauseeach user control instance is processed in its own sandbox, no variableconflicts occur. Instead, you get the page shown in FIGURE 4.
FIGURE 4: Each user controlinstance is rendered appropriately, without conflicts. Propertiesin user controls also can be exposed as Propertyobjects with Get and Set methods. This allows for codeexecution to occur when a property is either set or read. Create a new usercontrol named MyOtherUserControl.ascx and add the code shown in FIGURE 5. <%@ ImportNamespace="System.Data" %> <%@ ImportNamespace="System.Data.SqlClient" %> Private _table As String Public Property Text As String Get Return TextLabel.Text End Get Set TextLabel.Text = Value End SetEnd Property Public Property Table As String Get Return _table End Get Set _table = Value Dim SqlStmt As String = "SELECT TOP 2* FROM " & _table Dim conString As String = _ "server=localhost;database=Northwind;uid=sa;pwd=;" Dim con AsSqlConnection = New _ SqlConnection(conString) Dim cmd As SqlCommand =New _ SqlCommand(SqlStmt, con) con.Open() myGrid.DataSource = cmd.ExecuteReader() myGrid.DataBind() con.Close() End SetEnd Property Font-Bold="True" /> FIGURE 5:Exposing properties in a user control. The codein FIGURE 5 creates a new user control that exposes two properties, Text and Table. In the Textproperty declaration, set the value of the Textproperty (the value that was set either declaratively or programmatically) tothe Text property of a Label control. In the Get method of the property, you returnthe value of the Text property ofthe Label control. For amore complex example of how you can use Propertyobjects to execute code when a property is set, look at the Table property in FIGURE 5. First, youdeclare a private variable, _table,which is set to the value of the Tableproperty. The variable will maintain the value of the Table property for easy access in the user control. You use thevalue that was set to dynamically create a T-SQL SELECT command andexecute that command on a SqlConnection,calling SqlCommand.ExecuteReader toreturn a SqlDataReader object. Thatobject is set as the DataSourceproperty of a DataGrid. You bind theDataGrid and close the connection.When the user control s Tableproperty is set, this code executes, and the DataGrid is bound to the returned SqlDataReader. In the Getmethod of the Table property, youreturn the value of _table. To usethis new user control, create a new Web Form named WebForm2.aspx and add thecode from FIGURE 6. <%@ RegisterTagPrefix="DotNetJunkies" TagName="MyOtherUserControl" SRC="MyOtherUserControl.ascx"%> Text="This is the CustomersTable" Table="Customers"/>
Text="This is the ProductsTable" Table="Products" />
FIGURE 6:Setting user control properties declaratively. In theWeb Form, register the user control and place two instances of it on the page.In each instance, you declaratively set the values of the two publicly exposedproperties. Notice that if you attempt to set the _table variable from the Web Form, nothing will happen. This isbecause you declared the _tablevariable privately, and it is not accessible outside the user control. When yourequest this Web Form in a browser, the two properties for the user controlsare set, and the code in the Setmethod executes. See the resulting page, shown in FIGURE 7.
FIGURE 7: The user controlproperties determine the user control output. Exposing Methods Just asuser controls can expose properties, they also can expose methods. By exposinga public method in the user control, you can achieve the same functionality theTable property managed in theprevious user control. Create a new user control named MyThirdUserControl.ascx and add the code shown in FIGURE 8. <%@ ImportNamespace="System.Data" %> <%@ ImportNamespace="System.Data.SqlClient" %> Public Property Text As String Get Return TextLabel.Text End Get Set TextLabel.Text = Value End SetEnd Property Public SubGetData(_table As String) Dim SqlStmt As String = "SELECT TOP 2 *FROM " & _table Dim conString As String = _ "server=localhost;database=Northwind;uid=sa;pwd=;" Dim con As SqlConnection= New _ SqlConnection(conString) Dim cmd As SqlCommand =New _ SqlCommand(SqlStmt, con) con.Open() myGrid.DataSource = cmd.ExecuteReader() myGrid.DataBind() con.Close()End Sub Font-Bold="True"/> FIGURE 8:Exposing methods in user controls. In thiscode, you move the data-access functionality to a public method named GetData. This method takes the tablename as an argument and executes the same code from the previous example. You caninvoke publicly exposed methods of user controls programmatically from a WebForm. Create a new Web Form named WebForm3.aspx and add the code from FIGURE 9. <%@ RegisterTagPrefix="DotNetJunkies" TagName="MyThirdUserControl" SRC="MyThirdUserControl.ascx"%> Protected SubPage_Load(Sender As Object, E As EventArgs) UC1.Text="This is the CustomersTable" UC1.GetData("Customers") UC2.Text="This isthe Products Table" UC2.GetData("Products") End Sub id="UC1" />
id="UC2" />
FIGURE 9:Programmatically invoking user control methods. InWebForm3.aspx, you register the user control as in previous examples. When youplace the user control on the page, you add an ID value to it so you can accessit programmatically, like any control in ASP.NET. In the Page_Load event handler for the Web Form, you set the Text property of the user control byusing the syntax: ID.Property = Value Next,you invoke the GetData method withthe syntax: ID.Method(arguments) The resulting page looks identical to the page you saw in FIGURE7. The Benefits of Code-behind Usercontrols can be tied to a code-behind class in the same way Web Forms can. Thisallows for a clean separation of code and content. When using code-behind witha Web Form, the code-behind class is defined in the Page directive. Withuser controls, the Control directive is used because a user control doesnot inherit from the System.Web.UI.Pageclass, but rather from the System.Web.UI.UserControlclass. The attributes for the Control directive are the same as for the Pagedirective, with the exception of the Traceattribute which is not available in the Control directive. Tracing mustbe enabled at the page level, not the control level. You canconvert the user control MyThirdUserControl.ascxto use code-behind by making a few modifications. First, you must move all theprogrammatic code to a separate code-behind file named MyThirdUserControl.ascx.vb. (This follows the Visual Studio .NETnaming convention.) The code for this file can be found in FIGURE 10. Imports SystemImportsSystem.WebImportsSystem.Web.UIImportsSystem.Web.UI.WebControlsImportsSystem.Web.UI.HtmlControlsImportsSystem.DataImportsSystem.Data.SqlClient Public Class MyThirdUserControl : Inherits UserControl Protected TextLabel AsLabel Protected myGrid As DataGrid Public Property Text AsString Get Return TextLabel.Text End Get Set TextLabel.Text = Value End Set End Property Public Sub GetData(_table As String) DimSqlStmt As String = "SELECT TOP 2 * FROM " & _table Dim conString As String = _ "server=localhost;database=Northwind;uid=sa;pwd=;" Dim con AsSqlConnection = New _ SqlConnection(conString) Dim cmd As SqlCommand =New _ SqlCommand(SqlStmt, con) con.Open() myGrid.DataSource = cmd.ExecuteReader() myGrid.DataBind() con.Close() End Sub End ClassFIGURE 10:Creating a user control with a code-behind class. The usercontrol code-behind class looks nearly identical to a Web Form code-behindclass. The main difference is that the user control code-behind class inheritsfrom System.Web.UI.UserControl rather than System.Web.UI.Page.The .ascx file is now stripped of all programmatic code, leaving only UI code.The Control directive is needed totell the JIT compilers what code-behind class the user control inherits. And,if the code-behind class is not precompiled, you use the Src attribute to tell the JIT compiler where to find the classfile: <%@ ControlInherits="MyThirdUserControl" SRC="MyThirdUserControl.ascx.vb"%> Font-Bold="True" /> The Control directive uses the Inheritsattribute to identify the code-behind class this user control inherits, and theSrc attribute is used to tell the Visual Basic .NET JIT compiler whereto find the class file. When a Web Form that includes this user control isrequested, the code-behind class is JIT-compiled and saved in memory. Using Reflection to Discover User Control Properties and Methods Usercontrol properties and methods can be accessed programmatically from a Web Formcode-behind class, also. There are two ways to do this: If the user control isprecompiled, declare the user control in the code-behind class of the Web Formas an instance of the class: Protected UC1 As MyUserControl If theuser control is JIT compiled, as in the previous examples, you must usereflection to discover the class type of the user control and what propertiesand methods it exposes. This is because the .NET Framework does not knowanything about the user control class at compile time because the class has notbeen compiled yet. In this case, you must declare the user control in the WebForm code-behind file as an instance of its base type, System.Web.UI.UserControl: Protected UC1 As UserControl Usingreflection, the .NET Framework can discover and understand the class type,methods, and properties. Dealing with JIT-compiled user controls in a Web Formcode-behind class takes a little more code, but not much. The code in FIGURE 11is the code-behind class for WebForm4. Save this file as WebForm4.aspx.vb. Imports SystemImportsSystem.WebImportsSystem.Web.UIImportsSystem.Web.UI.WebControlsImportsSystem.Web.UI.HtmlControlsImportsSystem.Reflection Public Class WebForm4 : Inherits Page Protected UC1 AsUserControl Protected UC2 As UserControl Protected Sub Page_Load(Sender As Object, EAs EventArgs) Dim _uc1Type As Type = UC1.GetType() Dim _uc2Type As Type = UC2.GetType() Dim _uc1Text AsPropertyInfo = _ _uc1Type.GetProperty("Text") Dim _uc1GetData AsMethodInfo = _ _uc1Type.GetMethod("GetData") _uc1Text.SetValue(UC1, "This is theCustomers Table", _ Nothing) Dim argumentArray(0) Asstring argumentArray(0) = "Customers" _uc1GetData.Invoke(UC1, argumentArray) Dim _uc2Text AsPropertyInfo = _ _uc2Type.GetProperty("Text") Dim _uc2GetData AsMethodInfo = _ _uc2Type.GetMethod("GetData") _uc2Text.SetValue(UC2, "This is theProducts Table", _ Nothing) argumentArray(0) = "Products" _uc2GetData.Invoke(UC2, argumentArray) End SubEnd ClassFIGURE 11:Setting user control properties and invoking methods from code-behind usingreflection. InFIGURE 11 you declared two user controls, UC1 and UC2, asinstances of the System.Web.UI.UserControl class. In the Page_Load event handler for the WebForm, you use reflection to discover the class types and the publicly exposedproperties and methods of these user controls. First,you create a Type object and set it to the return value of the GetTypemethod exposed by the user controls. All objects in the .NET Framework exposethis method. It is inherited from the base System.Object class fromwhich all objects inherit. Usingthis Type object, you can probe for properties and methods as PropertyInfoand MethodInfo objects. The PropertyInfoobjects expose a SetValue method.The SetValue method takes threearguments: the ID of the object whose value is being set, the value to set, andan optional argument of index values for use when setting indexed properties.In FIGURE 11 SetValue is invokedonce for each user control, UC1 and UC2,to set their Text property values. TheVisual Basic .NET keyword Nothing isused for the third argument because you are not dealing with indexedproperties. The MethodInfo object exposes an Invoke method. This method takes twoarguments, the ID of the control whose method is being invoked, and an objectarray of method arguments. For the GetDatamethod the user control exposes only one argument is passed into the methodwhen it is invoked: the name of the table for the SELECT command. The PropertyInfo and MethodInfo objects are used, and the PropertyInfo.SetValueand MethodInfo.Invoke methods are invoked for each user control. The WebForm (WebForm4.aspx) that goes along with this code-behind class simplyinherits from the class and places two instances of the MyThirdUserControl user control on the form (see FIGURE 12). <%@ PageInherits="WebForm4" Src="WebForm4.aspx.vb" %> <%@ RegisterTagPrefix="DotNetJunkies" TagName="MyThirdUserControl" SRC="MyThirdUserControl.ascx" %> id="UC1" />
id="UC2" />
FIGURE 12:Using multiple instances of one user control. When you browse to the WebForm4.aspx, the resulting page isidentical to that shown in FIGURE 7. Using Precompiled User Controls and Known Classes Usingprecompiled code-behind classes with user controls does not require the use ofreflection because the user control s class type is known at compile time.Because the user control s type, properties, and methods also are known atcompile time, they are directly accessible in the Web Form code-behind class,as shown in FIGURE 13. Imports SystemImportsSystem.WebImportsSystem.Web.UIImportsSystem.Web.UI.WebControlsImportsSystem.Web.UI.HtmlControls Public Class WebForm5 : Inherits Page Protected UC1 AsCompiledUC Protected UC2 As CompiledUC Protected SubPage_Load(Sender As Object, E As EventArgs) UC1.Text = "Thisis the Customers Table" UC1.GetData("Customers") UC2.Text = "Thisis the Products Table" UC2.GetData("Products") End SubEnd ClassFIGURE 13:Setting precompiled user control properties programmatically from code-behind. The codeexample in FIGURE 13 assumes the class name for the user control was changedfrom MyThirdUserControl to CompiledUC, and the user control scode-behind class was compiled into a DLL and placed in the application s binfolder. Because the type CompiledUCis known when the Web Form is requested, the user control instances can bemapped directly to this class. As a result, the Text property and GetDatamethod are known and can be called directly without using reflection. Conclusion Usercontrols provide an easy means of writing reusable code and user interfaceelements. Like Web Forms, user controls can be created using any text editor.And, unlike custom server controls, they do not have to be compiled. In itssimplest form, a user control is just text that may be reused in an applicationin many places. In more complex user controls, properties and methods may beexposed, and complex code execution can occur. User controls support the .NETobject model, which allows for more power and flexibility than include filesprovide. Also, each user control is processed in its own sandbox, whichprevents naming and variable conflicts when more than one instance of the usercontrol appears in a single Web Form. Usercontrols are designed and intended for building reusable code modules whetherlogic only or logic and UI for use in a single Web application. When you needreusable code elements that can span application or machine boundaries, youshould use custom server controls instead of user controls. The files referenced in this article are available for download. Doug Seven is a co-founder of the .NET training companyDotNetJunkies.com. He came to DotNetJunkies.com by way of technical roles atNordstrom, Microsoft, and GiftCertificates.com and a position as trainingspecialist at Seattle Coffee Company. Seven co-authored Programming Data-Driven Web Applicationswith ASP.NETand ASP.NET: Tips,Tutorials, & Code, and is currently working on Professional ADO.NETand Building CustomControls for ASP.NET. Readers may contact him at mailto:[email protected]. Tell us what you think! Please send any comments about thisarticle to [email protected] include the article title and author.
About the Author
You May Also Like