User Controls

ASP.NET Makes Reusing Code Easy

asp:feature

Languages: VB

Technologies: User Controls | Code-behind | Reflection

 

User Controls

ASP.NET Makes Reusing Code Easy

 

By Doug Seven

 

ASP.NET and the .NET Framework introduce a new structure for building dynamic Web applications. In previous incarnations of ASP, developers became accustomed to working with server-side includes as a means of easy code reuse. They were the best thing available at the time, but using includes still came with problems:

  • Includes were processed in the same space as the page they were on, so variable conflicts were frequent.
  • An include file could be used only once on a page, so making controls that appeared multiple times on a page was cumbersome.
  • Includes did not support an object model that allowed for exposing properties and methods.

 

Although ASP.NET does support the use of includes, it also introduces a new means of encapsulating code for reuse: the user control.

 

In this article, you will learn what a user control is, what its advantages are, and how to build and interact with it. You ll start with some basic examples and build on them until you have made a complex user control that exposes properties and methods.

 

What Is a User Control?

The .NET Framework SDK documentation defines a user control as a user-authored server control that enables an ASP.NET page to be reused as a server control. A few modifications can turn any ASP.NET Web Form into a user control you ll learn more about that later. For now, understand that in its simplest form, a user control is no more than text saved in a separate file and used on a Web Form like any server control.

 

User controls provide an easy means of writing reusable logic and user-interface code. 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 .NET Framework identifies them as user controls based on this extension. User controls are compiled the first time they are used and are saved in memory the same way Web Forms are. One of the great advantages user controls have over includes is that user controls support the ASP.NET object model, which means they can expose properties and methods like any other object in the .NET Framework. User controls are designed for use in a single Web application, and are not designed to port across application boundaries. For reusable components that encapsulate logic and UI and are for use in multiple applications, use custom server controls.

 

Building a Basic User Control

As I said before, a user control is, in its simplest form, just text saved in a separate file that you can use on any Web Form in your application. You cannot navigate to user controls independently because they are only accessible as controls on a Web Form. Because of this, user controls should never contain ,

, and elements. Those elements will be in the Web Form.

 

To build a simple user control, open your favorite text editor and create a new file named MyUserControl.ascx. In this file, type the text This is my user control and save the file. That s it. You have created a user control. To use it, register it on a Web Form, which will enable you to place it on the Web Form just like any ASP.NET server control. Create a new Web Form named WebForm1.aspx in the same directory as the user control and add the code from FIGURE 1.

 

<%@ Register TagPrefix="DotNetJunkies"

    TagName="MyUserControl"

    Src="MyUserControl.ascx" %>

  

    

  

FIGURE 1: Registering a user control on a Web Form.

 

With this code, you register the user control on the Web Form using the @ Register directive. The three attributes of the @ Register directive are:

  • TagPrefix The prefix used when placing the control on the Web Form, similar to how asp is used to prefix intrinsic server controls.
  • TagName The name by which the control is referenced.
  • Src The absolute or relative location of the user control.

 

When you want 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 the user control on the page.

 

Exposing Properties

As with any object in the .NET Framework, user controls can expose properties. Once a user control exposes a property, you can access it either declaratively or programmatically. Creating properties for a user control is the same as creating properties for any object. Properties can be created as Public instances of a variable, or as Property objects with Get and Set methods.

 

Change the MyUserControl.aspx file to include the following code:

 

 

<%=Text %>

 

With this code, you create a public string variable named Text. This variable is accessible outside the user control because you declared it publicly. The code uses the <%= %> Response.Write shortcut to write the value of the Text variable. In the Web Form, you can set the value of the Text variable declaratively, as follows:

 

   Text="This is the Text property."   />

 

The resulting page is shown in FIGURE 2.

 


FIGURE 2: The user control is rendered as an HTML element within the page.

 

One of the advantages user controls have over include files is that user controls are processed in their own sandboxes. In other words, each instance of a user control is in an isolated processing space, which protects it from any variable conflicts. This enables multiple instances of the same user control on one Web Form, without any conflicts. Change WebForm1.aspx to use the code from FIGURE 3.

 

<%@ Register TagPrefix="DotNetJunkies"

  TagName="MyUserControl"

  SRC="MyUserControl.ascx" %>

  

    

     Text="This is the first user control." />

    

     Text="This is the second user control." />

    

     Text="This is the third user control." />

  

FIGURE 3: Using multiple instances of one user control.

 

In this Web Form, you use the same user control three times and provide a separate value for the Text property with each one. If you had tried to use the same include file three times in one ASP page, you would have raised the following error:

 

Microsoft VBScript compilation (0x800A0411)

Name redefined.

 

Because each user control instance is processed in its own sandbox, no variable conflicts occur. Instead, you get the page shown in FIGURE 4.

 


FIGURE 4: Each user control instance is rendered appropriately, without conflicts.

 

Properties in user controls also can be exposed as Property objects with Get and Set methods. This allows for code execution to occur when a property is either set or read. Create a new user control named MyOtherUserControl.ascx and add the code shown in FIGURE 5.

 

<%@ Import Namespace="System.Data" %>

<%@ Import Namespace="System.Data.SqlClient" %>

 

 

   Font-Bold="True" />

FIGURE 5: Exposing properties in a user control.

 

The code in FIGURE 5 creates a new user control that exposes two properties, Text and Table. In the Text property declaration, set the value of the Text property (the value that was set either declaratively or programmatically) to the Text property of a Label control. In the Get method of the property, you return the value of the Text property of the Label control.

 

For a more complex example of how you can use Property objects to execute code when a property is set, look at the Table property in FIGURE 5. First, you declare a private variable, _table, which is set to the value of the Table property. The variable will maintain the value of the Table property for easy access in the user control. You use the value that was set to dynamically create a T-SQL SELECT command and execute that command on a SqlConnection, calling SqlCommand.ExecuteReader to return a SqlDataReader object. That object is set as the DataSource property of a DataGrid. You bind the DataGrid and close the connection. When the user control s Table property is set, this code executes, and the DataGrid is bound to the returned SqlDataReader. In the Get method of the Table property, you return the value of _table.

 

To use this new user control, create a new Web Form named WebForm2.aspx and add the code from FIGURE 6.

 

<%@ Register TagPrefix="DotNetJunkies"

  TagName="MyOtherUserControl"

  SRC="MyOtherUserControl.ascx" %>

  

    

     Text="This is the Customers Table"

     Table="Customers" />

    

     Text="This is the Products Table"

     Table="Products"   />

  

FIGURE 6: Setting user control properties declaratively.

 

In the Web 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 exposed properties. Notice that if you attempt to set the _table variable from the Web Form, nothing will happen. This is because you declared the _table variable privately, and it is not accessible outside the user control.

 

When you request this Web Form in a browser, the two properties for the user controls are set, and the code in the Set method executes. See the resulting page, shown in FIGURE 7.

 


FIGURE 7: The user control properties determine the user control output.

 

Exposing Methods

Just as user controls can expose properties, they also can expose methods. By exposing a public method in the user control, you can achieve the same functionality the Table property managed in the previous user control. Create a new user control named MyThirdUserControl.ascx and add the code shown in FIGURE 8.

 

<%@ Import Namespace="System.Data" %>

<%@ Import Namespace="System.Data.SqlClient" %>

 

 

  Font-Bold="True" />

FIGURE 8: Exposing methods in user controls.

 

In this code, you move the data-access functionality to a public method named GetData. This method takes the table name as an argument and executes the same code from the previous example.

 

You can invoke publicly exposed methods of user controls programmatically from a Web Form. Create a new Web Form named WebForm3.aspx and add the code from FIGURE 9.

 

<%@ Register TagPrefix="DotNetJunkies"

  TagName="MyThirdUserControl"

  SRC="MyThirdUserControl.ascx" %>

  

 

  

    

     id="UC1" />

    

     id="UC2" />

  

FIGURE 9: Programmatically invoking user control methods.

 

In WebForm3.aspx, you register the user control as in previous examples. When you place the user control on the page, you add an ID value to it so you can access it 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 by using the syntax:

 

ID.Property = Value

 

Next, you invoke the GetData method with the syntax:

 

ID.Method(arguments)

 

The resulting page looks identical to the page you saw in FIGURE 7.

 

The Benefits of Code-behind

User controls can be tied to a code-behind class in the same way Web Forms can. This allows for a clean separation of code and content. When using code-behind with a Web Form, the code-behind class is defined in the Page directive. With user controls, the Control directive is used because a user control does not inherit from the System.Web.UI.Page class, but rather from the System.Web.UI.UserControl class. The attributes for the Control directive are the same as for the Page directive, with the exception of the Trace attribute which is not available in the Control directive. Tracing must be enabled at the page level, not the control level.

 

You can convert the user control MyThirdUserControl.ascx to use code-behind by making a few modifications. First, you must move all the programmatic code to a separate code-behind file named MyThirdUserControl.ascx.vb. (This follows the Visual Studio .NET naming convention.) The code for this file can be found in FIGURE 10.

 

Imports System

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.Web.UI.HtmlControls

Imports System.Data

Imports System.Data.SqlClient

 

Public Class MyThirdUserControl : Inherits UserControl

 

  Protected TextLabel As Label

  Protected myGrid As DataGrid

 

  Public Property Text As String

    Get

      Return TextLabel.Text

    End Get

 

    Set

      TextLabel.Text = Value

    End Set

  End Property

 

  Public Sub GetData(_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

 

End Class

FIGURE 10: Creating a user control with a code-behind class.

 

The user control code-behind class looks nearly identical to a Web Form code-behind class. The main difference is that the user control code-behind class inherits from 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 to tell 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 class file:

 

<%@ Control Inherits="MyThirdUserControl"

    SRC="MyThirdUserControl.ascx.vb" %>

 

  Font-Bold="True" />

 

The Control directive uses the Inherits attribute to identify the code-behind class this user control inherits, and the Src attribute is used to tell the Visual Basic .NET JIT compiler where to find the class file. When a Web Form that includes this user control is requested, the code-behind class is JIT-compiled and saved in memory.

 

Using Reflection to Discover User Control Properties and Methods

User control properties and methods can be accessed programmatically from a Web Form code-behind class, also. There are two ways to do this: If the user control is precompiled, declare the user control in the code-behind class of the Web Form as an instance of the class:

 

Protected UC1 As MyUserControl

 

If the user control is JIT compiled, as in the previous examples, you must use reflection to discover the class type of the user control and what properties and methods it exposes. This is because the .NET Framework does not know anything about the user control class at compile time because the class has not been compiled yet. In this case, you must declare the user control in the Web Form code-behind file as an instance of its base type, System.Web.UI.UserControl:

 

Protected UC1 As UserControl

 

Using reflection, the .NET Framework can discover and understand the class type, methods, and properties. Dealing with JIT-compiled user controls in a Web Form code-behind class takes a little more code, but not much. The code in FIGURE 11 is the code-behind class for WebForm4. Save this file as WebForm4.aspx.vb.

 

Imports System

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.Web.UI.HtmlControls

Imports System.Reflection

 

Public Class WebForm4 : Inherits Page

 

  Protected UC1 As UserControl

  Protected UC2 As UserControl

 

  Protected Sub Page_Load(Sender As Object, E As EventArgs)

    Dim _uc1Type As Type = UC1.GetType()

    Dim _uc2Type As Type = UC2.GetType()

 

    Dim _uc1Text As PropertyInfo = _

      _uc1Type.GetProperty("Text")

    Dim _uc1GetData As MethodInfo = _

      _uc1Type.GetMethod("GetData")

 

    _uc1Text.SetValue(UC1, "This is the Customers Table", _

       Nothing)

 

    Dim argumentArray(0) As string

    argumentArray(0) = "Customers"

    _uc1GetData.Invoke(UC1, argumentArray)

 

    Dim _uc2Text As PropertyInfo = _

      _uc2Type.GetProperty("Text")

    Dim _uc2GetData As MethodInfo = _

      _uc2Type.GetMethod("GetData")

 

    _uc2Text.SetValue(UC2, "This is the Products Table", _

      Nothing)

 

    argumentArray(0) = "Products"

    _uc2GetData.Invoke(UC2, argumentArray)

 

  End Sub

End Class

FIGURE 11: Setting user control properties and invoking methods from code-behind using reflection.

 

In FIGURE 11 you declared two user controls, UC1 and UC2, as instances of the System.Web.UI.UserControl class. In the Page_Load event handler for the Web Form, you use reflection to discover the class types and the publicly exposed properties and methods of these user controls.

 

First, you create a Type object and set it to the return value of the GetType method exposed by the user controls. All objects in the .NET Framework expose this method. It is inherited from the base System.Object class from which all objects inherit.

 

Using this Type object, you can probe for properties and methods as PropertyInfo and MethodInfo objects. The PropertyInfo objects expose a SetValue method. The SetValue method takes three arguments: the ID of the object whose value is being set, the value to set, and an optional argument of index values for use when setting indexed properties. In FIGURE 11 SetValue is invoked once for each user control, UC1 and UC2, to set their Text property values. The Visual Basic .NET keyword Nothing is used for the third argument because you are not dealing with indexed properties.

 

The MethodInfo object exposes an Invoke method. This method takes two arguments, the ID of the control whose method is being invoked, and an object array of method arguments. For the GetData method the user control exposes only one argument is passed into the method when it is invoked: the name of the table for the SELECT command.

 

The PropertyInfo and MethodInfo objects are used, and the PropertyInfo.SetValue and MethodInfo.Invoke methods are invoked for each user control.

 

The Web Form (WebForm4.aspx) that goes along with this code-behind class simply inherits from the class and places two instances of the MyThirdUserControl user control on the form (see FIGURE 12).

 

<%@ Page Inherits="WebForm4" Src="WebForm4.aspx.vb" %>

<%@ Register TagPrefix="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 is identical to that shown in FIGURE 7.

 

Using Precompiled User Controls and Known Classes

Using precompiled code-behind classes with user controls does not require the use of reflection because the user control s class type is known at compile time. Because the user control s type, properties, and methods also are known at compile time, they are directly accessible in the Web Form code-behind class, as shown in FIGURE 13.

 

Imports System

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.Web.UI.HtmlControls

 

Public Class WebForm5 : Inherits Page

 

  Protected UC1 As CompiledUC

  Protected UC2 As CompiledUC

 

  Protected Sub Page_Load(Sender As Object, E As EventArgs)

 

    UC1.Text = "This is the Customers Table"

    UC1.GetData("Customers")

 

    UC2.Text = "This is the Products Table"

    UC2.GetData("Products")

 

  End Sub

End Class

FIGURE 13: Setting precompiled user control properties programmatically from code-behind.

 

The code example in FIGURE 13 assumes the class name for the user control was changed from MyThirdUserControl to CompiledUC, and the user control s code-behind class was compiled into a DLL and placed in the application s \bin folder. Because the type CompiledUC is known when the Web Form is requested, the user control instances can be mapped directly to this class. As a result, the Text property and GetData method are known and can be called directly without using reflection.

 

Conclusion

User controls provide an easy means of writing reusable code and user interface elements. 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 its simplest form, a user control is just text that may be reused in an application in many places. In more complex user controls, properties and methods may be exposed, and complex code execution can occur. User controls support the .NET object model, which allows for more power and flexibility than include files provide. Also, each user control is processed in its own sandbox, which prevents naming and variable conflicts when more than one instance of the user control appears in a single Web Form.

 

User controls are designed and intended for building reusable code modules whether logic only or logic and UI for use in a single Web application. When you need reusable code elements that can span application or machine boundaries, you should 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 company DotNetJunkies.com. He came to DotNetJunkies.com by way of technical roles at Nordstrom, Microsoft, and GiftCertificates.com and a position as training specialist at Seattle Coffee Company. Seven co-authored Programming Data-Driven Web Applications with ASP.NET and ASP.NET: Tips, Tutorials, & Code, and is currently working on Professional ADO.NET and Building Custom Controls for ASP.NET. Readers may contact him at mailto:[email protected].

 

Tell us what you think! Please send any comments about this article to [email protected]. Please include the article title and author.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish