In the past, implementing custom-built controls was tricky, especially on large-scale systems where complex registration procedures might be required to use them. Even on simple systems, the coding required to create a custom control could become a very involved process. The scripting capabilities of older Web languages also suffered by not giving you complete access to your cunningly crafted object models, which resulted in poor performance.
The .NET Framework provides an ideal setting for the creation of custom controls, using simple programming techniques, Every aspect of ASP.NETserver controls is exposed for you to customize, including such capabilities as templating and client-side scripting. However, there is no need to write code for all of these eventualities; simpler controls can be a lot easier to create.
In addition, the dynamic discovery of assemblies that is inherent in a .NET system makes installation of Web applications on a new Web server as simple as copying the directory structure containing your code, To make use of the controls you have created, you simply copy the assemblies containing those controls along with the rest of the code. Youcan even place frequently used controls in an assembly located in the global assembly cache (GAC)on the Web server, so that all Web applications on the server have access to them.
This chapter discusses two different kinds of controls:
- User controls (and how to convert existing ASP.NETpages into controls)
- Custom controls (and how to group the functionality of several controls, extend existing controls, and create new controls from scratch)
User controls are illustrated with a simple control that displays a card suit (club, diamond, heart, or spade), so that you can embed it in other ASP.NETpages with ease, We won’t go into too much depth for custom controls, although we will show you the basic principles and direct you to your information beyond this book.
User controls are controls .that you create using ASP.NETcode, just as you use in standard ASP.NET Webpages. The difference is that after you have created a user control you can reuse it in multiple ASP.NETpages.
For example, say that you have created a page that displays some information from a database, perhaps information about an order. Instead of creating a fixed page that does this, it is possible to place the relevant code into a user control, and then insert ·that control into as many different Webpages as you want.
Tn addition, it is possible to define properties and methods for user controls. For example, you can specify a property for the background color for displaying your database table in a Webpage, or a method to re-run a database query to check for changes.
To start, you create a simple user control, As is the case with the other chapters, you can download the code for the sample projects in this chapter from the csharpWeb site at www.csharpaid.com.
A Simple User Control
In Visual Studio .NET,create a new Web site called PCSUserCWebAppl in the directory C: \ ProCSharp \ After the standard files have been generated, select the Website → Add New Item menu option and add a WebUser Control called PCS UserCl. ascx, as shown in Figure 38-1.
The files added to your project, with the extensions. ascx and ascx work in a very similar way to the aspx files that you have seen already The ascx file contains your ASP.NETcode and looks very similar to a normal. aspx file The ascx. cs file is your code-behind file, which defines custom code for the user control, much in the same way that forms are extended by .aspx cs files.
The ascx files can be viewed in Design or Source view, just like. aspx files. Looking at the file in sourceview reveals an important difference: there is no HTML code present, and in particular no <form> element. This is because user controls are inserted inside ASP.NETforms in other files and so don’t need a <form> tag of their own. The generated code is as follows:
Control Language=”C# AutoEventWireup=”true” CodeFile=”PCSUserCl.asex.cs·
This is very similar to the <%@Page %>directive generated in aspx files, except that Control is specified rather than Page, The CodeFile attribute specifies the code-behind file and Inherits specifies the class defined in the code-behind file from which the page inherits. The code in the ascx. cs file contains, as in auto-generated. aspx. cs files, a class definition that is empty apart from a Page_Load () event handler method.
Your simple control will be one that displays a graphic corresponding to one of the four standard suits in cards (club, diamond, heart, or spade), The graphics required for this were shipped as part of a previous version of Visual Studio .NET you can find them in the downloadable code, in the CardSuitImages directory, with the file names CLUB. BMP, DIAMOND. BMP, HEART. BMP, and SPADE. BMP. Copy these files into a new Images subdirectory of your project’s directory, so that you can use them in a moment, If you do not have accessto this download, you can use any images you like for this example because they are not important to the functionality of the code.
Note that unlike earlier versions of Visual Studio, changes you make to the Web site structure outside of Visual Studio are automatically reflected in the IDE, You have to hit the refresh button in the Solution Explorer window, but you should see the new Images directory and bitmap files appear automatically.
Now add some code to your new control. In the HTML view of.PCSUserCl ascx, add the following:
This defines a default state for your control, which is a picture of a club along with a label. The – in the path to the image means “start at the root directory of the Web site.” Before you add functionality, you will test this default by adding this control to your project Web page webForml .aspx.
To use a custom control in an aspx file, you first need to specify how you will refer to it, that is, the name of the tag that will represent the control in your HTML, To do this, you use the <%@ Register directive at the top of the code in Default .aspx, as follows:
<%@ Register TagPrefix=’pcs’ TagName=”UserCl” Src=”PCSUserCl.ascx’ %>
The TagPrefix and TagName attributes specify the tag name to use (in the form <TagPrefix: TagName», and you use the Src attribute to point to the file containing your user control. Now you can use the control by adding the following element:
<form id=”Forml’ method=’post” runat=’server’>
<pcs:UserCl Runat=”server” ID=”myUserControl/>
This is all you need to do to test your user control. Figure 38-2shows the results of running this code.
As it stands, this control groups two existing controls, an image and a label, in a table layout. Therefore, it falls into the category of a composite control.
To gain control over the displayed suit, you can use an attribute on the <pcs: UserCl> element, Attributes on user control elements are automatically mapped to properties on user controls, so all you have to do to make this work is add a property to the code behind your control, PCSUserCl. ascx. cs. Call this property Suit, and let it take any suit value. To make it easier for you to represent the state of the control, you define an enumeration to hold the four suit names. The best way to do this is to add an App_Code directory to your Web site, and then add a . cs file called Sui t. cs in this directory. App_Code is another “special” directory, like App_Data, whose functionality is defined for you – in this case it holds additional code files for your Web application. You can add this directory by right-clicking the Web site Solution Explorer and clicking Add ASP.NETFolder Q App_Code. When you have done this, add suit cs with code as follows:
public enum suit
club, diamond, heart, spade
The PCSUserCl class needs a member variable to hold the suit type, current Suit:
public partial class PCSUserCl : System.web.UI;userControl
protected suit currentSuit;
And a property to access this member variable, suit:
The set accessor here sets the URL of the image to one of the files you copied earlier, and the text displayed to the suit name.
Next, you must add code to Default, aspx so that you can access this new property, You could simply specify the suit using the property you have just added:
<PCS:UserCl Runat=·server~ id=·myUserControl· Suit=~diamond·/>
The ASP.NETprocessor is intelligent enough to get the correct enumeration item from the string provided, To make things a bit more interesting and interactive, though, you will use a radio button list to select a suit:
You also need to add an event handler for the SelectedlndexChanged event of the list, which you can do simply by double-clicking the radio button list control in Design view.
Note that you have set the AutoPostBack property of this list to True, because the suitList_SelectedlndexChanged () event handler won’t be executed on the server unless a postback is in operation, and this control doesn’t trigger a postback by default.
The suitList_SelectedlndexChanged () method requires the following code in Default.aspx. cs:
You know that the Value attributes on the <Listitem> elements represent valid values for the suit enumeration you defined earlier, so you simply parse these as enumeration types and use them as values of the Suit property of your user control. You cast the returned object type to suit using simple casing syntax, because this cannot be achieved implicitly.
Now you can change the suit when you run your Web application (see Figure 38-3).
Next, you give your control some methods, Again, this is very simple; you just add methods to the PCSUserCl class:
These four methods – Club (),Diamond (),Heart (),and Spade () – change the suit displayed on the screen to the respectivesuitclicked.
You call these functions from four lmageBut ton controls in your. aspx page:
You use the following event handlers:
Note that you could use a single event handler for all four buttons, because they have identical method signatures, You could detect which button has been pressed by the value passed to sender, and thus determine which method of myUserControl to call and which index to set dynamically, In this case, though, there wouldn’t be a huge difference in the amount of code required, so,for simplicity, things are kept separate.
Now you have four new buttons you can use to change the suit, as shown in Figure 38-4.
Now that you have created your user control, you can use it in any other Web page simply by using the <%@ Register %> directive and the two source code files (PCSUserCl. ascx and PCSUserCl. ascx. cs) you have created for the control.
User Coolro/s In PCSDemoSite
In the PCSDemoSite, the meeting room booker application from the previous chapter has been converted into a user control for ease of reuse. To see the control, you have to log in to the site as User, with password User!!!, and navigate to the Meeting Room Booker page, as shown in Figure 38-5.
Apart from the obvious change in style, which is achieved by themes, as you see later in this chapter, the major modifications are as follows:
- The usename is automatically taken from user details.
- There is no extra data display at the bottom of the page, and corresponding DataBind () calls are removed from the code behind.
- There is no result label beneath the control- the user gets enough feedback by seeing events added to the calendar and event list, without being told that event addition was successful.
- The page containing the user control uses a master page.
The code modifications to achieve all of this are remarkably Simple. You won’t look at them here, but you will come back to this control later in the chapter, when you look at logging in.
Custom controls go a step beyond user controls in that they are entirely self-contained in C# assemblies, requiring no separate ASP.NETcode. This means that you don’t need to go through the process of assembling a user interface (UI) in anascx file. Instead, you have complete control over what is written to the output stream, that is, the exact HTRML generated by your control.
In general, it will take longer to develop custom controls than user controls because the syntax is more complex, and you often have to write significantly more code to get results, A user control may be as simple as a few other controls grouped together, as you have seen, whereas a custom control can do just about anything short of making you a cup of coffee.
To get the most customizable behavior for your custom controls, you can derive a class from System .Web. UI .WebControls. WebControl. If you do this, you are creating a full custom control. Alternatively, you can extend the functionality of an existing control, creating a derived custom control. Finally, you can group existing controls together, much as you did in the last section but with a more logical structure, to create a composite custom control.
Whatever you create can be used in ASP.NET pages in pretty much the same way. All you need to do is place the generated assembly in a location where the Web application that will use it can find it, and register the element names to use with the <%@ Register %> directive. For this location, you have two options: you can either put the assembly in the bin directory of the Web application, or place it in the GAC if you want all Web applications on the server to have access to it. Alternatively, if you are just using a user control on a single Web site, you can just put the . cs file for the control in the App_Code directory for the site.
The <%@ Register %> directive takes a slightly different syntax for custom controls:
<%@ Register TagPrefix=’PCS’ Namespace=’PCSCustomWebControls’
Youuse the TagPrefix option in the same way as before, but you don’t use the TagNarneor Src attributes. This is because the custom control assembly you use may contain several custom controls, and each of these will be named by its class, so redundant. In addition, because you can use the dynamic discovery capabilities of the Framework to find your assembly, you simply have to name it and the namespace in it that contains your controls.
In the previous line of code, you are instructing the program to use an assembly called CustomWebControls dll with controls in the PCSCustomWebControls namespace, and use the tag prefix PCS if you have a control called Control in this namespace, you could use it with the ASP.NET code
<PCS:Controll Runat=”server” ID=”MyControll”/>
The Assembly attribute of the <%@Register %>directive is optional- if you have custom controls in t he App_Code directory of your site, you can omit this, and the Web site will look at code here for controls. One thing though – the Namespace attribute is not optional. You must include a namespace in code files for custom controls, or the ASP.NET runtime will not be able to find them.
With custom controls, it is also possible to reproduce some of the control nesting behavior that exists in list controls, for example the way that you can nest <asp: List Item> controls inside a list control to populate the list control:
You can create controls that should be interpreted as being children of other controls in a very similar way to this This is one of the more advanced techniques that you won’t be looking at in this book.
Custom Control Sample
Now it’s time to put some of this theory into practice. You will use a single Web site called PCSCustomCWebApplin the C: \ProCSharp\Chapter \ directory, with a custom control inits App_ Code directory to illustrate a simple custom control. The control here will be a multicolored version of the existing Label control, with the ability to cycle through a set of colors for each letter in its text.
The code for the control, RainbowLabel, in the file App_Code\ Rainbow cs, starts with the following using statements:
Apart from System’. Drawing, these are the default namespaces that are added when you add a class file to a Web site. The System. Drawing namespace is required for the Color enumeration, The class maintains an array of colors to use for letters in its text in a private Color array called colors:
Also notice that the namespace PCSCustomWebControls is used to contain the control. As discussed earlier, this is necessary so that Web pages can reference the control correctly.
To enable color cycling, you also store an integer offset value in a private offset property:
Note that this property isn’t as simple as just storing a value in a member field. This is due to the way ASP.NETmaintains state, as discussed in the previous chapter. Controls are instantiated on each postback operation, so to store values you must make use of view state. This is easy to access – you simply use the ViewState collection, which can store any object that is serializable. Otherwise, offset would revert to its initial value between each postback.
To modify offset, you use a method called Cycle ():
public void Cycle()
offset = ++offset;
This simply increments the value stored in the view state for offset.
Finally, you come to perhaps the most important method override for any custom control- Render ( ), This is where you output HTML, and as such it can be a very complicated method to implement. If you were to take into account all the browsers that may view your controls,and all the variables that could affect rendering,this method could get very big.Fortunately,for this example, it’s quite simple:
This method gives you access to the output stream to display your controlcontent, There are only two caseswhere you don’t need to implement this method:
- When you are designing a controlthathas no visualrepresentation (usuallyknown as a component)
- When you are deriving from an existing control and don’t need to change its display characteristics
Custom control scan also expose custom methods, raise custom events,and respond to child controls (if any).In the case of Rainbow Label, you don’t have to worry about any of this.
Next, you need to modify Default. aspx to view the control and provide access to Cycle (),as follows:
Now you can view the sample and cycle the colors in the sample text, as shown in Figure 38-6.
You can do a lot more with custom controls;indeed, the possibilities are practically limitless, but you will have to experiment with these possibilities on your own.