Creating ASP.NET User Controls

I l @ ve RuBoard

Creating ASP.NET User Controls

We create user controls much the same way that we create normal Web forms in ASP.NET; however, we normally denote that a file is to be used as a control by saving it with an .ascx file extension. Let's look at an example of a simple user control.

 <asp:label text="Welcome to ASP.NET User Controls" runat="Server"/> 

Yes, that's it. That's our entire control. Note that it's nothing more really than a Web form fragment, and in our control definition file we do not include <html> , <head> , <body> , or <form runat="server"> tags. Listing 9.1 shows how we use our control on a Web form.

Listing 9.1 Implementing the User Control on a Web Form (91.aspx)
 <%@ Page language="c#"%> <%@ Register TagPrefix="ASPNETByExample" TagName="Welcome" src="welcome.ascx" %> <html>   <body>     <form method="post" runat="server">         <ASPNETByExample:Welcome runat="server"/>     </form>   </body> </html> 
Figure 9.1. The output of Listing 9.1, a simple welcome message user control.

This control simply provides a label displaying our static welcome text. Let's look at another example to see how we would include script in our control to render a dynamic welcome message. Listing 9.2 includes the updated control to render a different welcome message depending on the time of day.

Listing 9.2 User Control to Display Dynamic Welcome Message Based on Time of Day (timeofdaywelcome.ascx)
 <script language="c#" runat="server">     void Page_Load(Object sender, EventArgs e)     {         int CurrentHour =  System.DateTime.Now.Hour;         String WelcomeMessage = "";         if (CurrentHour < 12) {             WelcomeMessage = "Good Morning";         }         else if ((CurrentHour > 12) && (CurrentHour < 18)){             WelcomeMessage = "Good Afternoon";         }         else {             WelcomeMessage = "Good Evening";         }         Message.Text = WelcomeMessage;     } </script> <asp:label id="Message" runat="Server"/> 
Figure 9.2. The output of Listing 9.2, the updated welcome message control (92.aspx).

Now you will note that the control determines which of three possible greetings to render based on the time of day the user accesses the page. As in ASP 3.0 include files, our script is kept neatly in a control definition file which keeps our Web forms easier to manage.

At this point, you're probably wondering how user controls are much of an improvement over include files. You may have noticed that while we now have a descriptive tag to place on our Web form instead of a generic include statement, we've actually had to write more code to include this welcome message than we would have using include files under ASP 3.0. Now we'll begin to cover some of the features which set user controls apart from the include directive in earlier versions of ASP.

Creating Code-behind User Controls

Up until this point, the user controls we've been working with have contained both the declarative presentation markup and program logic in the same file. Just like ASP.NET Web forms, however, user controls support code-behind files. This allows us to make maintenance easier by separating the program logic and presentation markup into different files.

Now let's take our previous time-of-day user control and convert it into a code-behind user control. To do so, we remove everything except the presentation markup. This leaves us with a simple label control:

 <asp:label id="Message" runat="Server"/> 

Next , we create the code-behind file with the appropriate file extensions (either .cs for C# controls or .vb for VB.NET controls). We then include the system namespaces required for working with Web controls. In C# we do so with the using statement:

 using System; using System.Web.UI; using System.Web.UI.WebControls; 

In VB.NET, we reference the appropriate namespaces via the Imports statement:

 Imports System Imports System.Web.UI Imports System.Web.UI.WebControls 

Next we create a class for our user control that inherits from System.Web.UI.UserControl :

 class TimeOfDayControl : UserControl { } 

Or in VB.NET:

 Class TimeOfDayControl     Inherits UserControl End Class 

Once we've created the derived class, we need to declare instance variables for each server control in the .ascx file. Next, we need to add the appropriate code the class body to provide the functionality for the user control. We do this by moving the code over from our original control file. Listings 9.3 and 9.4 show the complete code-behind files.

Listing 9.3 C# Version of the Time of Day Code-behind Control (timeofdayctl.cs)
 using System; using System.Web.UI; using System.Web.UI.WebControls; class TimeOfDayControl : UserControl {     public Label Message;     void Page_Load(Object sender, EventArgs e)     {         int CurrentHour =  System.DateTime.Now.Hour;         String WelcomeMessage = "";         if (CurrentHour < 12) {             WelcomeMessage = "Good Morning";         }         else if ((CurrentHour > 12) && (CurrentHour < 18)){             WelcomeMessage = "Good Afternoon";         }         else {             WelcomeMessage = "Good Evening";         }         Message.Text = WelcomeMessage;     } } 
Listing 9.4 VB.NET Version of the Time of Day Code-behind Control (timeofdayctl.vb)
 Imports System Imports System.Web.UI Imports System.Web.UI.WebControls Class TimeOfDayControl     Inherits UserControl     Public Message As Label;     Sub Page_Load(sender As Object, e As EventArgs)         Dim CurrentHour As Integer =  System.DateTime.Now.Hour         Dim WelcomeMessage As String = ""         If (CurrentHour < 12) Then             WelcomeMessage = "Good Morning"         ElseIf ((CurrentHour > 12) And (CurrentHour < 18)) Then             WelcomeMessage = "Good Afternoon"         Else             WelcomeMessage = "Good Evening"         End If         Message.Text = WelcomeMessage     End Sub End Class 

Finally, we need to specify the code-behind file in the .ascx file. We do this with a simple @Control directive at the top of the file:

 <%@ control inherits = "TimeOfDayControl" src=" timeofdayctl.cs" %> 

Or for the VB.NET version:

 <%@ control inherits = "TimeOfDayControl" src=" timeofdayctl.vb" %> 

Note that both versions of these code-behind controls are functionally equivalent to our previous example. Next, we'll look at how to expose properties from user controls.

Defining Properties in User Controls

As we mentioned earlier, one of the handy features of the ASP 3.0 include statement was the ability to reuse portions of code across multiple ASP pages. However, since include files are processed before the containing ASP page is executed, code in included files is executed as if it were included inline within the containing page. This means that blocks of included code act more or less like parts grafted onto an ASP page. This can present a number of problems including these:

  • Variable scope issues between includes that use the <%%> syntax versus the <SCRIPT RUNAT=SERVER></SCRIPT> tags.

  • No good way to dynamically include files. Include files can be conditionally executed; however, all includes are processed before the page executes so large include files are processed regardless of whether they're executed.

  • While the ASP engine will not allow duplicate variables to be declared, duplicate function declarations do not produce an error, which can lead to unexpected results.

With ASP.NET user controls, developers can now encapsulate logic within self-contained components that allow for more sophisticated code reuse by setting property values and making method calls. Listing 9.5 shows an example of a login user control that exposes properties to the containing form.

Listing 9.5 Login User Control (login.ascx)
 <script language="c#" runat="server">     private Boolean m_Secure = false;     public String WelcomeMessage = "Welcome";     void Login_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             UnsecurePanel.Visible = false;             Message.Text = WelcomeMessage + ", " + UserName.Text;             SecurePanel.Visible = true;             m_Secure = true;         }     }     void Logout_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             UnsecurePanel.Visible = true;             UserName.Text = "";             Password.Text = "";             SecurePanel.Visible = false;             m_Secure = false;         }     }     public Boolean Secure{         get{             return m_Secure;         }         set{             m_Secure = value;         }     } </script> <asp:panel id="UnsecurePanel" runat="Server">     <asp:label runat="server" font-size="9pt">Username: </asp:label>     <br>     <asp:textbox id="UserName" runat="server" />     <br>     <asp:requiredfieldvalidator id="UsernameValidator"          runat="server"  controltovalidate="UserName"          errormessage="Please enter a username" style="color: red; font-size: 8pt"  />    <br>     <asp:label runat="server" font-size="9pt">Password: </asp:label>     <br>     <asp:textbox id="Password" runat="server" textmode="Password" />     <br>     <asp:requiredfieldvalidator id="PasswordValidator" runat="server"          controltovalidate="Password"          errormessage="Please enter a password"          style="color: red; font-size: 8pt" />     <br>     <asp:button id="Login" text="Login" runat="server" onclick="Login_Click"/> </asp:panel> <asp:panel id="SecurePanel" runat="Server" visible="false">     <asp:label id="Message" runat="server"/><br>     <asp:linkbutton id="Logout" runat="server" onclick="Logout_Click" text="Logout" style="font-size: 8pt; color: blue;"/> </asp:panel> 

Figure 9.3 shows the output of Listing 9.5.

Figure 9.3. The output of Listing 9.5, the login user control (login.ascx).

Notice that the login control exposes two properties, Secure which we have defined using the get...set syntax to be read-only and WelcomeMessage as a public instance variable. We can set the WelcomeMessage property in a couple of ways. Normally we would want to set the required property values when declaring the control like this:

 <ASPNETByExample:login id="UserLogin" runat="server" WelcomeMessage="Greetings"/> 

Often, however, we need to set property values at runtime based on user input or some other dynamic value. We do this by setting the property value as we would any other property value:

 UserLogin.WelcomeMessage = "Welcome"; 

Defining Methods in User Controls

We have seen how to expose properties from user controls, but there may be scenarios when it makes sense to expose methods to the containing Web form. To do so, we only need to declare our functions as public . Let's look at an updated version in Listing 9.6 of our login control to which we've add a new Logoff method.

Listing 9.6 Updated Login Control with Logoff Method (login2.ascx)
 <script language="c#" runat="server">     private Boolean m_Secure = false;     public String WelcomeMessage = "Welcome";     void Login_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             UnsecurePanel.Visible = false;             Message.Text = WelcomeMessage + ", " + UserName.Text;             SecurePanel.Visible = true;             m_Secure = true;         }     }     void Logout_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             Logoff();         }     }     public Boolean Secure{         get{             return m_Secure;         }     }     public void Logoff(){         UnsecurePanel.Visible = true;         UserName.Text = "";         Password.Text = "";         SecurePanel.Visible = false;         m_Secure = false;     } </script> <asp:panel id="UnsecurePanel" runat="Server">     <asp:label runat="server" font-size="9pt">Username: </asp:label><br><asp:textbox id="UserName" runat="server" /><br>     <asp:requiredfieldvalidator id="UsernameValidator" runat="server" controltovalidate="UserName" errormessage="Please enter a username" style="color: red; font-size: 8pt"  /><br>     <asp:label runat="server" font-size="9pt">Password: </asp:label><br><asp:textbox id="Password" runat="server" textmode="Password" /><br>     <asp:requiredfieldvalidator id="PasswordValidator" runat="server" controltovalidate="Password" errormessage="Please enter a password" style="color: red; font-size: 8pt" /><br>     <asp:button id="Login" text="Login" runat="server" onclick="Login_Click"/> </asp:panel> <asp:panel id="SecurePanel" runat="Server" visible="false">     <asp:label id="Message" runat="server"/><br>     <asp:linkbutton id="Logout" runat="server" onclick="Logout_Click" text="Logout" style="font-size: 8pt; color: blue;"/> </asp:panel> 

Now that we've added the Logoff method to our login control, we need to add code to our containing Web form to call the method. Listing 9.7 shows this modified Web form. Figure 9.4 displays the updated login control.

Figure 9.4. The output of Listing 9.6, the updated login control (login2.ascx).

Listing 9.7 Updated Web Form That Calls the Logoff Method of the Login User Control (86.aspx)
 <%@ Page language="c#"  %> <%@ Register TagPrefix="ASPNETByExample" TagName="Login" src="login2.ascx" %> <html> <head> <script runat=server>     void Logoff_Click(Object sender, EventArgs e){         UserLogin.Logoff();     } </script>   </head>   <body>     <form method="post" runat="server">         <ASPNETByExample:login id="UserLogin" runat="server" WelcomeMessage="Greetings"/>         <br>         <br>         <br>         <asp:button id="Logoff" runat="Server" text="Sign out" onclick="Logoff_Click" />      </form>   </body> </html> 

You'll note in this example we now can log the user off programmatically by calling the Logoff method of the user control. In our example, we test this functionality by calling Logoff from the event handler of a button on our containing page. In an actual application, however, perhaps the method would become more useful if called after a timeout check to determine if the user's current session had expired .

Raising Events from User Controls

In the previous examples we've discussed how the containing Web form communicates with user controls. There are occasions, however, when a user control needs to alert the containing Web form that its state has changed so that other controls on the form can be updated. We'll now examine how we create events in ASP.NET user controls.

Creating events in ASP.NET involves the following steps:

  • Define a class that contains the data for the event (optional).

  • Create an event delegate, a special object that allows an event sender to be connected to an event handler.

  • Create a public event member whose type is an event delegate.

  • Create a protected method that raises the event.

Let's look at each of these steps a little more in detail before we set out to create an event for our user control.

You've already become quite familiar with handling events for many of the built-in objects in ASP.NET. You may have noticed that the signatures for many of these event handlers are the same. Let's take a look at the Page_Load event as an example:

 void Page_Load(Object sender, EventArgs e) 

As with all ASP.NET event handlers, the first argument is the sender, or object that created the event. The second argument is the data for the event. In this example, the class is of type System.EventArgs , the base class for all event data in the .NET platform. We'll look at creating a custom class for event data a little later. The important thing to note here is that the data for your event must be of type System.EventArgs or derive from it.

After you have determined the class that will contain the data for your event, the next step in providing event functionality for your control is to create the event delegate. A delegate acts as a go-between for your control and the handler for your custom event. For those of you with C++ experience, delegates are similar to function pointers without many of the drawbacks. We will not spend too much time covering delegates in this context so please refer to the resources listed in this text to explore delegates further.

To create an event delegate we simply define the signature of the event handler:

 public delegate void  EventName  Handler(Object sender,  EventDataType  e); 

Therefore, for an event named Click , our delegate would be defined as

 public delegate void ClickHandler(Object sender, ClickEventArgs e); 

After we have defined the delegate for our custom event, the next step in providing event functionality is to create a public event member whose type is the event delegate we just created. In the case of our Click event, our public event member would be defined as

 public event ClickHandler Click; 

Next, we create a protected method on our control that raises the event. The method must be named On<EventName>, so in our example, our method would be named OnClick. Listing 9.8 shows the method definition.

Listing 9.8 Protected OnClick Method to Raise the Click Event
 protected virtual void OnClick(ClickEventArgs e) {     if(Click != null){         Click(this, e); // invokes the delegate     } } 

The last step in providing custom events for your user control is to actually raise the event. To do so, we simply create an instance of the class that is to contain the event data and then call the protected method we just defined, passing it the event data. Listing 9.9 illustrates this step.

Listing 9.9 Creating the Event Data Class and Firing the Event
 EventArgs evt = new EventArgs(); OnClick(evt); 

For our Click example, we have selected the base class System.EventArgs to contain our event data. We'll cover firing events with custom event data classes in a later chapter.

Up until this point, our discussion of user control events may seem rather abstract. Let's walk through an example and put our theory into practice by adding event functionality to our login control. Please review the updated control in Listing 9.10 before we discuss the modifications.

Listing 9.10 Raising Events from a User Control (login3.ascx)
 <script language="c#" runat="server">     private Boolean m_Secure = false;     public String WelcomeMessage = "Welcome";     void LoginButton_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             UnsecurePanel.Visible = false;             Message.Text = WelcomeMessage + ", " + UserName.Text;             SecurePanel.Visible = true;             m_Secure = true;             EventArgs evt = new EventArgs();             OnLogin(evt);         }     }     void LogoutButton_Click(Object sender, EventArgs e){         if (UsernameValidator.IsValid && PasswordValidator.IsValid){             Logoff();         }     }     public Boolean Secure{         get{             return m_Secure;         }     }     public String User{         get{             return UserName.Text;         }     }     public void Logoff(){         UnsecurePanel.Visible = true;         UserName.Text = "";         Password.Text = "";         SecurePanel.Visible = false;         m_Secure = false;         EventArgs evt = new EventArgs();         OnLogout(evt);     }     // *** Define the Login Event     // Delegate declaration     public delegate void LoginHandler(object sender, EventArgs e);     // Event declaration     public event LoginHandler Login;     // Raise the event by invoking the delegate,     // sending "this", the current instance  of the class.     protected virtual void OnLogin(EventArgs e) {     if (Login != null) {        Login(this, e);//Invokes the delegates.           }     }     // *** Define the Logout event     // Delegate declaration     public delegate void LogoutHandler(object sender, EventArgs e);     // Event declaration     public event LogoutHandler Logout;     // Raise the event by invoking the delegate,     // sending "this", the current instance  of the class.     protected virtual void OnLogout(EventArgs e) {     if (Logout != null) {        Logout(this, e);//Invokes the delegates.           }     } </script> <asp:panel id="UnsecurePanel" runat="Server">     <asp:label runat="server" font-size="9pt">Username: </asp:label><br><asp:textbox id="UserName" runat="server" /><br>     <asp:requiredfieldvalidator id="UsernameValidator" runat="server" controltovalidate="UserName" errormessage="Please enter a username" style="color: red; font-size: 8pt"  /><br>     <asp:label runat="server" font-size="9pt">Password: </asp:label><br><asp:textbox id="Password" runat="server" textmode="Password" /><br>     <asp:requiredfieldvalidator id="PasswordValidator" runat="server" controltovalidate="Password" errormessage="Please enter a password" style="color: red; font-size: 8pt" /><br>     <asp:button id="LoginButton" text="Login" runat="server" onclick="LoginButton_Click"/> </asp:panel> <asp:panel id="SecurePanel" runat="Server" visible="false">     <asp:label id="Message" runat="server"/><br>     <asp:linkbutton id="LogoutButton" runat="server" onclick="LogoutButton_Click" text="Logout" style="font-size: 8pt; color: blue;"/> </asp:panel> 

You'll notice that in this example, we've extended our login user control example by adding two events, Login and Logout . Since these two custom events are declared in the same manner, we'll only walk through the steps in creating the Login event.

Since we are using the base System.EventArgs class to contain our event data, the first step in creating the Login event is to define our event delegate. In our example, we create our event delegate, LoginHandler as

 public delegate void LoginHandler(object sender, EventArgs e); 

Next, we create the public event member with the following syntax:

 public event LoginHandler Login; 

Note the type of this public event member is that of LoginHandler , the event delegate we created in the first step. Next we create a protected method to raise the event:

 protected virtual void OnLogin(EventArgs e) {     if (Login != null) {        Login(this, e);  //  Invokes the delegate.     } } 

Finally, now that we are finished defining our custom Login event, we need to add code to fire the event at the appropriate time. We want to raise the Login event after the username and password have been validated , so we have added two new lines of code to our LoginButton_Click event handler:

 EventArgs evt = new EventArgs(); OnLogin(evt); 

In these two lines we simply create an instance of the System.EventArgs base class to contain our event data, and then we pass this event data to our protected OnLogin method. We now have a functional Login event for our login control. To test this new functionality, let's add an event handler for the Login event to our containing Web form.

If you will recall, we had added a sign-out button to our Web form to test our Logoff method. To test our new event functionality, let's hide or show this button based on whether the user is signed-in or not. To do so, we add two event handlers to our Web form:

 void UserLogin_Login(Object sender, EventArgs e) {     LogoffButton.Visible = true; } void UserLogin_Logout(Object sender, EventArgs e) {     LogoffButton.Visible = false; } 

We create each of these event handlers as we have for the built-in events we have worked with until this point. Following convention, we name our event handler as the name of our control concatenated with an underscore and the name of our event. Our handler has no return type and its arguments must match those of the event delegate we created when defining the event from within our user control. Listing 9.11 contains the complete updated Web form. Figure 9.5 shows the output of this listing.

Figure 9.5. The output of Listing 9.11, showing and hiding the sign-out button by handling the Login and Logout events.

Listing 9.11 Updated Web Form with Event Handlers for the New Login and Logout Events (98.aspx)
 <%@ Page language="c#"  %> <%@ Register TagPrefix="ASPNETByExample" TagName="Login" src="login2.ascx" %> <html> <head> <script runat=server>     void LogoffButton_Click(Object sender, EventArgs e){         UserLogin.Logoff();     }     void UserLogin_Login(Object sender, EventArgs e)     {         LogoffButton.Visible = true;     }     void UserLogin_Logout(Object sender, EventArgs e)     {         LogoffButton.Visible = false;     } </script>   </head>   <body>     <form method="post" runat="server">         <ASPNETByExample:login id="UserLogin" runat="server" WelcomeMessage="Greetings"/>         <br>         <br>         <br>         <asp:button id="LogoffButton" runat="Server" text="Sign out" onclick="LogoffButton_Click" />      </form>   </body> </html> 
I l @ ve RuBoard


Asp. Net. By Example
ASP.NET by Example
ISBN: 0789725622
EAN: 2147483647
Year: 2001
Pages: 154

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net