All About ASP.NET User Controls...
If your are not making use of User Controls in your web applications you probably should be. They can save you many key strokes and help you immensely with maintaining a consistent design between pages of your application.
In building and maintaining the DotNetJohn.com website I don't know what I would have done without User Controls. Please take a moment and examine the layout of this webpage. The top of the page down through the horizontal menu bar is a User Control. The whole left side navigation system is a User Control. The top-right side showing the three advertisements is a User Control. Below that is another User Control showing partner sites (which is consuming a web service hosted at AspAlliance.com). At the bottom of the page there is a group of radio buttons and request to rate this article. That is a User Control. The footer for the page below that is also a User Control. That is a total of six User Controls on this page (and virtually all other pages on this site). I can make a change to any of these User Controls and the change is instantly reflected on over 100 pages on the site!
In this article we build a very simple User Control and then build upon it to demonstrate how to add read-only properties, read-write properties, sub routines and events to the control.
Building the User Control is very easy. It can contain html, script, and can use code-behind pretty much like an aspx page. The difference is that it is saved with an .ascx extension. If you are using a plain text editor just save the file as SomeName.ascx. If you are using Visual Studio select Add New and then Web User Control as the type of file to build. You cannot render a User Control in the browser. It must be registered within an .aspx page. We will see how to do that when we show the code, which is the next thing we will talk about.
The User Control we will build for this article is a simple two label, two textbox form which could be used for database logins. First the code for the User Control (UCControls.ascx). Strictly speaking the <@ Control line at the top is not even necessary in this particular control, but I like to leave it in for clarity. As you can see, this control is not much different than html you might see on a .aspx page. It is just not completely well formed as far as an html page goes (no opening html tag, body tag, etc.).
|
<%@ Control Language="vb" %> <div align="center"> <table style="font: 10pt verdana; border-width:1; border-style:solid;" cellspacing="10"> <tr> <td> <asp:Label id="lblUserName" Font-Bold="true" Text="User Name:" runat="server" /> </td> <td> <asp:TextBox id="txtUserName" runat="server" /> </td> </tr> <tr> <td> <asp:Label id="lblPassword" Font-Bold="true" Text="Password:" runat="server" /> </td> <td> <asp:TextBox id="txtPassword" TextMode="Password" runat="server" /> </td> </tr> </table> </div> |
Now for our .aspx page which will include our User Control. Notice on the second line that we must register our User Control. We give a TagPrefix of any name we choose. We also give it a TagName of anything we want. Most importantly, we must state the name (Src), and possibly the path, of the User Control file. Try to be logical with your names. TagPrefix might be your company's initials. TagName might be some logical name for the type of control such as Header, Footer, TopMenu, etc.
Registering the control is the first step. The second step is to define the control in code, in the spot where you want it to show on the page. Notice about 3/4's down the page the line <DNJ:LoginControl id="UC1" runat="server" />. This is the same syntax as if you were defining an Asp:TextBox or some other intrinisic control. The difference is that you are using TagPrefix:TagName instead of Asp:ControlName. You then give it an ID of your choice and specify runat="server". That is all you have to do. If you ever have to refer to the User Control in code (and we will further down in the article), you refer to it using the ID ("UC1" in this case).
|
<%@ Page Language=VB %> <%@ Register TagPrefix="DNJ" TagName="LoginControl" Src="UCControls.ascx" %> <html> <head> <title>Implementing a User Control</title> <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0"> <meta name="CODE_LANGUAGE" content="Visual Basic 7.0"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body> <p></p> <form id="form1" runat="server"> <DNJ:LoginControl id="UC1" runat="server" /> </form> </body> </html> |
You may run the program here.
There may be times when you need to read some property of a User Control. Although the User Control becomes a part of your .aspx page it is still a separate object and its properties are not available to the .aspx page unless they are specifically exposed. We will now take a look at how to expose readonly properties.
This next User Control is identical to the first one with the exception of the top line. We are going to use code-behind on the .ascx page to expose the values of the UserName and Password textbox values by writing Public Property Gets. First the code for UCReadProp.ascx without further comment.
|
<%@ Control Language="vb" AutoEventWireup="false" Src="UCReadProp.ascx.vb" Inherits="UCReadProp" %> <div align="center"> <table style="font: 10pt verdana; border-width:1; border-style:solid;" cellspacing="10"> <tr> <td> <asp:Label id="lblUserName" runat="server" Font-Bold="true" Text="User Name: " /> </td> <td> <asp:TextBox id="txtUserName" runat=server /> </td> </tr> <tr> <td> <asp:Label id="lblPassword" runat="server" Font-Bold="true" Text="Password: " /> </td> <td> <asp:TextBox id="txtPassword" runat="server" TextMode="Password" /> </td> </tr> </table> </div> |
Next is the code-behind file UCReadProp.ascx.vb. All we are doing here is setting two variables, "UserName" and "Password" to the values of their respective textbox controls.
|
Public MustInherit Class UCReadProp Inherits System.Web.UI.UserControl Protected txtUserName As System.Web.UI.WebControls.TextBox Protected txtPassword As System.Web.UI.WebControls.TextBox Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Public ReadOnly Property UserName() As String Get UserName = txtUserName.Text End Get End Property Public ReadOnly Property Password() As String Get Password = txtPassword.Text End Get End Property End Class |
Now for the .aspx page UCReadProp.aspx. The differences between this and the first aspx page we looked at is that we have added a submit button and an OnClick event handler as well as a label control to hold the results of our property gets. Notice that all we have to do to get the property values is to refer to UC1.PropertyName. This calls the property get routines in the .ascx code-behind and returns the values of the respective textboxes.
|
<%@ Page Language="vb" %> <%@ Register TagPrefix="DNJ" TagName="LoginControl" Src="UCReadProp.ascx" %> <script runat="server"> Sub BtnSubmit_Click(Sender As Object, e As EventArgs) lblMessage.Text = "Username: " & UC1.UserName _ & "<br>Password: " & UC1.Password End Sub </script> <html> <head> <title>User Control With Read Only Properties</title> <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0"> <meta name="CODE_LANGUAGE" content="Visual Basic 7.0"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body> <form id="form1" runat="server"> <p></p> <DNJ:LoginControl id="UC1" runat="server" /> <BR> <div align="center"> <asp:button id="btnSubmit" text="Submit" OnClick="BtnSubmit_Click" runat="server" /> <p></p> <asp:label id="lblMessage" runat="server" /> </div> </form> </body> </html> |
You may run the program here.
This next example incorporates our readonly properties from above, but also adds some writeonly properties and some readwrite properties. I'm not going to spend much time explaining each of the properties - you should be able to figure them out from the code. I will tell you in overview form what all the program does. First the .ascx file (UCReadWriteProp.ascx) which is identical to the previous one except for the name of the code-behind file.
|
<%@ Control Language="vb" AutoEventWireup="false" Src="UCReadWriteProp.ascx.vb" Inherits="UCReadWriteProp" %> <div align="center"> <table style="font: 10pt verdana; border-width:1; border-style:solid;" cellspacing="10"> <tr> <td> <asp:Label id="lblUserName" runat="server" Font-Bold="true" Text="User Name:" /> </td> <td> <asp:TextBox id="txtUserName" runat="server" /> </td> </tr> <tr> <td> <asp:Label id="lblPassword" runat="server" Font-Bold="true" Text="Password:" /> </td> <td> <asp:TextBox id="txtPassword" runat="server" TextMode="Password" /> </td> </tr> </table> </div> |
Now for the UCReadWriteProp.ascx.vb code-behind page with all the property gets and sets in it. Our readonly properties are still there, but now there are some writeonly properties as well as readwrite properties. I'll leave it to you to figure out what they all do. Remember that the variable to hold a value is in the Property line, while the value itself is in the Get or Set line in the code.
|
Public MustInherit Class UCReadWriteProp Inherits System.Web.UI.UserControl Protected txtUserName As System.Web.UI.WebControls.TextBox Protected txtPassword As System.Web.UI.WebControls.TextBox Protected lblUserName As System.Web.UI.WebControls.Label Protected lblPassword As System.Web.UI.WebControls.Label Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Public ReadOnly Property UserName() As String Get UserName = txtUserName.Text End Get End Property Public ReadOnly Property Password() As String Get Password = txtPassword.Text End Get End Property Public WriteOnly Property FontName() As String Set lblUserName.Font.Name = value lblPassword.Font.Name = value End Set End Property Public WriteOnly Property FontBold() As Boolean Set lblUserName.Font.Bold = value lblPassword.Font.Bold = value End Set End Property Public Property UserNameLabel() As String Get UserNameLabel = lblUserName.Text End Get Set lblUserName.Text = value End Set End Property Public Property PasswordLabel() As String Get PasswordLabel = lblPassword.Text End Get Set lblPassword.Text = value End Set End Property End Class |
Finally we come to UCReadWriteProp.aspx. First of all, notice about 3/4's down the page where we define the user control. We are setting two properties, FontName and FontBold. FontName is set to Garamond and FontBold is set to false. When the page first renders our UserName and Password labels in the User Control will be in Garamond and not bolded. Now look at the BtnSubmit_Click handler near the top of the page. There you will see the lines UC1.FontName = "Verdana" and UC1.FontBold = "True". After the submit button is clicked, the fonts will change as you will see. Also notice in the Page_Load event that we check to see if the propery UserNameLabel has the value "User Name:". If it does, then we change it to "Type Your Name:". These are examples of using the property Gets and Sets in the User Control's code-behind page.
|
<%@ Page Language="vb" %> <%@ Register TagPrefix="DNJ" TagName="LoginControl" Src="UCReadWriteProp.ascx" %> <script runat="server"> Sub Page_Load(ByVal Sender as Object, ByVal E as EventArgs) If UC1.UserNameLabel = "User Name:" Then UC1.UserNameLabel = "Type Your Name:" End If End Sub Sub BtnSubmit_Click(Sender As Object, E As EventArgs) lblMessage.Text = "User Name: " & UC1.UserName _ & "<br>Password: " & UC1.Password UC1.FontName = "Verdana" UC1.FontBold = "True" End Sub </script> <html> <head> <title>Read/Write Properties in a UserControl</title> <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0"> <meta name="CODE_LANGUAGE" content="Visual Basic 7.0"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body> <form id="form1" runat="server"> <p></p> <DNJ:LoginControl id="UC1" FontName="Garamond" FontBold="False" runat="server" /> <br> <div align="center"> <asp:button id="btnSubmit" text="Submit" OnClick="BtnSubmit_Click" runat="server" /> <p></p> <asp:label id="lblMessage" runat="server" /> </div> </form> </body> </html> |
You may run the program here.
One last example. In the following program we will demonstrate how the .aspx page can call a subroutine in the User Control. In this example we place a button on the .aspx page which will call a subroutine in the User Control's code-behind page to clear the text in the UserName and Password text boxes. The submit button will not do anything at all. First the User Control UCSub.ascx.
|
<%@ Control Language="vb" AutoEventWireup="false" Src="UCSub.ascx.vb" Inherits="UCSub" %> <div align="center"> <table style="font: 10pt verdana; border-width:1; border-style:solid;" cellspacing="10"> <tr> <td> <asp:Label id="lblUserName" runat="server" Font-Bold="true" Text="User Name:" /> </td> <td> <asp:TextBox id="txtUserName" runat="server" /> </td> </tr> <tr> <td> <asp:Label id="lblPassword" Font-Bold="True" Text="Password:" runat="server" /> </td> <td> <asp:TextBox id="txtPassword" TextMode="Password" runat="server" /> </td> </tr> </table> </div> |
Now for the code-behind file UCSub.ascx.vb. Notice that we have a simple subroutine to clear the UserName and Password textbox controls.
|
Public MustInherit Class UCSub Inherits System.Web.UI.UserControl Protected txtUserName As System.Web.UI.WebControls.TextBox Protected txtPassword As System.Web.UI.WebControls.TextBox Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Public Sub ClearText() txtUserName.Text = "" txtPassword.Text = "" End Sub End Class |
Lastly we come to the UCSub.aspx page. It is much like our other pages except that it has a button reading "Clear Text" that calls UC1.ClearText() in the User Control's code-behind file.
|
<%@ Page Language="vb" %> <%@ Register TagPrefix="DNJ" TagName="LoginControl" Src="UCSub.ascx" %> <script runat="server"> Sub btnSubmit_Click(Sender As Object, e As EventArgs) End Sub Sub btnClearText_Click(sender As Object, e As EventArgs) UC1.ClearText() End Sub </script> <html> <head> <title>Using a Sub routine in a UserControl</TITLE> <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0"> <meta name="CODE_LANGUAGE" content="Visual Basic 7.0"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body> <form id="form1" runat="server"> <p></p> <DNJ:LoginControl id="UC1" runat="server" /> <BR> <div align="center"> <asp:Button id="btnSubmit" text="Submit" onclick="BtnSubmit_Click" runat="server" /> <asp:Button id="btnClearText" text="Clear Text" OnClick="btnClearText_Click" runat="server" /> <p></p> <asp:label id="lblMessage" runat="server" /> </div> </form> </body> </html> |
You may download all the code here.
I strongly urge you to incorporate User Control in your applications. They are invaluable. I certainly don't know how I could manage dotnetjohn.com without them.