Build a User Control

The simplest type of control you can build is a User control, which is essentially an ASPX page changed to have an .ascx extension. When you install .NET, it prevents IIS from displaying files with an .ascx extension directly, so users can't request your User controls by themselves.

So that you can see all the differences, it's useful to attempt to change a Web Form into a User control (that is, change an ASPX page into an ASCX page). For example, create a Web Form called testChange.aspx, place a Button control on it, and set the button's Text property to My Button.

Add a client-side script to display an alert when a user clicks the button. For example:

private void Button1 Click(object sender, System.EventArgs e) {

this.Page.RegisterStartupScript("msg", "<script language='JScript'>" + "alert('My Button clicked!');</script>");

Next, right-click the testChange.aspx file and select the Rename item from the pop-up menu. Change the file's extension to .ascx. You'll see a warning about changing file extensions. Answer Yes to accept the change. When you save your changes, the code-behind class and the RESX file also are renamed to reflect the changed extension, but just renaming the file isn't quite enough. After renaming the file, you have just four manual changes to make to change the Web Form into a User control:

1. User controls inherit from System.Web.UI.UserControl rather than System.Web.UI.Page. In the code-behind file, change the class definition public class testChange : System.Web.UI.Page to public class testChange : System.Web.UI.UserControl

2. Although Visual Studio changes the name of the associated code-behind file, it doesn't change the reference to it in the ASPX file. Open the testChange.ascx file in the HTML editor, then change the Codebehind attribute in the top line from

Codebehind="testChange.aspx.cs"

Codebehind="testChange.ascx.cs"

3. Change the Page attribute in the top line to Control. Now, you no longer have a Page object; you have a Control object.

4. Remove the <form> tag but not the <asp:Button> tag. Actually, this last step is not really required—the rule is, you can't have two <form> tags in a Web Form that run at the server, so it's perfectly OK to leave the <form> tag in place, but you must remove the runat="server" attribute. However, for simple controls, it's easier not to deal with the added complexity of forms embedded in forms; normally you should remove the <form> tag. In this particular case, it doesn't matter.

Now test the new User control in a Web Form. Create a new Web Form in the ch2 3 folder and name it ch23-1.aspx. In HTML mode, change the id attribute of the <form> tag to Form1. In the code-behind file, add this line to the Form_Load method:

this.FindControl("Form1").Controls.Add

((ch2 3.testChange) this.LoadControl("testChange.ascx"));

When you compile and run the Web Form, you'll see the button from your User control in the browser window. When you click it, you'll see the JavaScript alert (see Figure 23.1).

t-wi- on a ei^njnw

K lijHw. ^ 0-SC?

*3

Mi j

Hvhibn

r ■> i

J

«

■i

33 »M

i-ta

Figure 23.1: The ch2 3-1.aspx Web Form contains an instance of the User control testChange.ascx, which displays an alert when you click the button

Figure 23.1: The ch2 3-1.aspx Web Form contains an instance of the User control testChange.ascx, which displays an alert when you click the button

Creating a Web Form and then changing it to a User control is one easy way to create a User control. You may be thinking, "But there's a User control file type in the Add Item dialog!" That's true—I'll show you that in a minute. But changing a Web Form into a User control shows you how few differences there are between the two types. Also, after you've built a Web Form, you may at some point realize that it would be better implemented as a User control. Now you know how to accomplish the change.

To compare the two approaches, you should try building a User control directly. Add a new User control to your CSharpASP project in the ch2 3 folder. Name the control prettyXML.ascx.

Tip You can't create a User control with a name like 23-1—VS doesn't allow dashes in class names.

This time, you'll create a read-only control that can display any XML file in "pretty-print" form in a TextBox control on any Web Form. You can control the XML file URL and the size and position of the TextBox. The User control itself is very simple: It contains one TextBox Web Server control named txtXML. It doesn't matter where you place the control on the Web Control design surface because it won't appear in that position anyway—you can provide an absolute position if you wish, or use FlowLayout mode to position the TextBox as you would any other HTML control.

Listing 23.1 contains the HTML for the prettyXML.ascx file.

Listing 23.1: HTML for the prettyXML.ascx File (prettyXML.ascx)

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="prettyXML.ascx.cs" Inherits="CSharpASP.ch23.prettyXML"

targetSchema="http://schemas.microsoft.com/intellisense/ie5"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML>

<meta content="Microsoft Visual Studio.NET 7.0" name="GENERATOR">

<meta content="Visual Basic 7.0" name="CODE_LANGUAGE"> <meta content="JavaScript" name="vs defaultClientScript"> <meta content="http://schemas.microsoft.com/intellisense/ie5"

name="vs targetSchema"> </HEAD> _

<body MS_POSITIONING="GridLayout"> form id="Form1" method="post">

<asp:TextBox id="txtXML" TextMode="MultiLine" EnableViewState="False" ReadOnly="True"

runat="server"> </asp:TextBox> </form> </body> </HTML>

All the code in Listing 23.1 is VS generated except for the <asp:textbox> Web control tag. I included it here so that you can see that the control is absolutely plain; it has no style attribute and no rows or cols attributes—no layout attributes whatsoever. The only attributes it contains are ReadOnly="True", EnableViewState="False" , and TextMode="MultiLine".These three attributes enforce the control's purpose: to display (not to provide editable) XML documents in read-only mode. When designing a control, you should change hats: Stop thinking in Web Form designer mode and start thinking in control author mode. As a control author, your job is to expose as much functionality to the potential users of your control as possible. At the same time, you want to set reasonable defaults. In this case, because you want the control to be read-only, it's reasonable to enforce that at the control level. But the control doesn't contain style attributes or other display settings because it's reasonable to use the default TextBox control settings unless the user overrides them.

When developers use your control, they need to be able to pass the filename of an XML file to display, so you must add a property. Add a private string variable named mXMLFile and a public property named XMLFile to the code-behind class file.

// private class level member variable private String mXMLFile="";

// public property public String XMLFile { get{

return mXMLFile;

mXMLFile = value;

When the Web Form runs, you want the control to open the XML file, read it, and format it as a string that you can place into the TextBox. The getPrettyXML method accepts an XML filename and returns the formatted string containing the document formatted with indented elements—much as you'd see the document if you loaded it into IE:

public String getPrettyXML(String aFilename ) { if (aFilename != null) {

FileInfo aFile = new FileInfo(aFilename); if (aFile.Exists) {

StringBuilder sb = new StringBuilder((int)

aFile.Length * 2); XmlDocument doc = new XmlDocument(); const int indent = 3; doc.Load(XMLFile);

XmlTextWriter writer = new XmlTextWriter

(new StringWriter(sb)); writer.Formatting = Formatting.Indented; writer.Indentation=indent; doc.WriteContentTo(writer); return sb.ToString();

return null;

return null;

The preceding code snippet creates a StringBuilder to hold the formatted XML, creates a DOMDocument, loads the file, and then creates an XmlTextWriter object named writer that formats and writes the content. The last three lines do all the work. The first tells the XmlTextWriter to create indented XML output:

writer.Formatting = Formatting.Indented;

Next, the code uses a Microsoft-specific DOM extension called WriteContentTo that writes the XML content of an XmlDocument to an XmlTextWriter:

doc.WriteContentTo(writer);

Finally, because the XmlTextWriter object writes the content to a StringBuilder (the variable sb), the method just returns the StringBuilder's text contents:

return sb.ToString();

Tip This code illustrates a very convenient trick, because it's not as easy as you might think to format and indent an XML file with custom code.

Finally, you should override the Render method to call the getPrettyXML routine and fill the TextBox with the results. In addition, you want to "pick up" any style attributes that the control user set in the ASPX file and apply them to the TextBox control. By adding the style attributes at render time, you give the control user the capability to set the look and position of your control. When you override a control method, you should normally call the base method as well.

protected override void Render(System.Web.UI.HtmlTextWriter writer)

txtXML.Text = getPrettyXML(XMLFile); // allow style attributes override if (this.Attributes.CssStyle != null) {

foreach(string key in this.Attributes.CssStyle.Keys) { aValue = this.Attributes.CssStyle[key]; txtXML.Attributes.CssStyle.Add(key, aValue);

base.Render(writer);

The last line calls base.Render, passing the HtmlTextWriter object received by the Render event. That's a specific decision. I decided that the TextBox control should render even if the control user doesn't set the XMLFile property, which gives the user a visual clue (because the control renders an empty TextBox) that the XMLFile property is missing. However, it's equally valid to decide that the control shouldn't render anything. You can accomplish that by moving the base.Render method call inside the first if block, as in the following altered version:

protected override void Render(System.Web.UI.HtmlTextWriter writer)

txtXML.Text = getPrettyXML(XMLFile); // allow style attributes override if (this.Attributes.CssStyle != null) {

foreach(string key in this.Attributes.CssStyle.Keys) { aValue = this.Attributes.CssStyle[key]; txtXML.Attributes.CssStyle.Add(key, aValue);

base.Render(writer);

Now you need to create a Web Form to test the control. Create a new Web Form named ch2 3-2.aspx, change the default form id attribute to Form1, and drag the prettyXML.ascx item from the Server Explorer to the design surface. It should look like Figure 23.2.

Figure 23.2: Web Form designer surface with prettyXML.ascx User control

Note that you can't drag a User control and place it where you want, and the representation of the User control in the Web Form doesn't look like the control you just built. That's a User control limitation. Don't worry about the look of the control in the designer. Click the User control and then look at the Properties box. You won't see the XMLFile property for the User control either, despite the fact that the property is public—that's another limitation. Rather than setting properties in the property browser and defining the look and position of the User control in the designer, you must work directly with the HTML. Change the designer to HTML mode. The HTML for the completed Web Form looks like Listing 23.2.

Note Be sure to correct the hard-coded path in Listing 23.2 if it doesn't match that required for your server.

Listing 23.2: HTML Code for the ch23-2.aspx Web Form That Displays the prettyXML User Control (ch23-2.aspx)

<%@ Page language="c#" Codebehind="ch23-2.aspx.cs"

AutoEventWireup="false" Inherits="CSharpASP.ch23.ch23_2" %> <%@ Register TagPrefix="uc1" TagName="prettyXML" Src="prettyXML.ascx" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML>

<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0"> <meta name="CODE_LANGUAGE" Content="C#">

<meta name="vs defaultClientScript" content="JavaScript"> <meta name="vs targetSchema"

content="http://schemas.microsoft.com/intellisense/ie5">

<body MS_POSITIONING="GridLayout">

form id="Form1" method="post" runat="server"> <uc1:prettyXML id="PrettyXML1" runat="server"

XMLFile="c:\inetpub\wwwroot\CSharpASP\ch23\people.xml"> </uc1:prettyXML>

The highlighted lines define, insert, and format the prettyXML User control. The first highlighted line defines the tag and code location for the control:

<%@ Register TagPrefix="uc1" TagName="prettyXML" Src="prettyXML.ascx" %>

The @ Register directive defines the XML tag (uc1:prettyXML). TagPrefix controls the portion of the tag before the colon; TagName controls the portion of the tag after the colon. The names you see here are the default names (uc1 stands for User control 1) inserted by VS when you drop a User control onto a Web Form, but you are free to change them to anything you like. Similarly, the Src attribute, in this case, contains only a filename because the control is in the same project folder as the Web Form, but the Src attribute accepts a relative URL for any location in the same project.

Tip User controls must be in the same project as the Web Form that references them. If you want to reuse a User control, copy it into your current project.

When you run the Web Form, you'll see a small multiline text (a <textarea>) control containing the people.xml file contents. That doesn't look very nice. Try making the control bigger by creating a style attribute for the <uc1:prettyXML> tag. For example, change the tag so it looks like this:

<uc1:prettyXML id="PrettyXML1" runat="server"

XMLFile="c:\inetpub\wwwroot\CSharpASP\ch2 3\people.xml" style="position: absolute; left: 50: top: 50; width: 500; height: 500;">

</uc1:prettyXML>

The highlighted code shows the added style attribute. Save the changes and request the Web Form again from your browser. This time, the generated <textarea> tag is large enough for you to see the XML contents clearly. Note that the contents are read-only as defined in the User control itself. In addition, the control doesn't maintain ViewState because the EnableViewState attribute in the prettyXML.ascx file is set to false.

Was this article helpful?

0 0

Post a comment