ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: ASP.NET in a Nutshell

User Controls and Custom Server Controls, Part 3

Related Reading

ASP.NET in a Nutshell
By G. Andrew Duthie, Matthew MacDonald

by Matthew MacDonald and G. Andrew Duthie

Editor's note: In part three of four in this series of book excerpts from ASP.NET in a Nutshell, continue to learn more about server controls.


Adding Design-Time Support

While using the Blog control in a Web Forms page is fairly simple, it's still not 100 percent intuitive. For example, without documentation, there's no way for someone using the Blog control to know what the appropriate values for the Mode property are. Without explicitly telling developers using the control about the Add mode, it would be difficult for them to discover and use this mode on their own.

For developers using Visual Studio .NET (or another IDE that supports IntelliSense), you can solve this problem by adding design-time support to the control. This is done by using a combination of special metadata attributes added to the control and custom XSD schemas to support IntelliSense statement completion for Web Forms pages. IntelliSense support in code-behind modules is automatic and requires no additional coding.

Part of the challenge of providing design-time support for custom server controls is that different editors in the Visual Studio IDE require different techniques to support design-time functionality. Custom controls automatically support IntelliSense statement completion when working with code-behind modules in Visual Basic .NET or C#. Figure 6-3 shows this statement completion in action for the Blog control.

Figure 6-3. IntelliSense in code-behind

 

Unfortunately, when editing Web Forms pages, automatic support for statement completion does not extend to the Design or HTML views (nor does Visual Studio provide built-in support for viewing and editing properties in the Property browser without additional work in your control). To complicate things further, one technique is necessary for supporting IntelliSense in the Property browser and Design view of the Web Forms editor, while another is necessary for supporting it in the HTML view of the Web Forms editor.

In This Series

User Controls and Custom Server Controls, Part 4
In this final installment in a series of excerpts from ASP.NET in a Nutshell, learn how to share ASP.NET controls across applications.

User Controls and Custom Server Controls, Part 2
In Part 2 in this series of excerpts from ASP.NET in a Nutshell, learn ASP.NET custom server controls.

User Controls and Custom Server Controls, Part 1
In part one from this series of book excerpts from ASP.NET in a Nutshell, get an overview on ASP.NET controls, and learn about ASP.NET user controls.

The technique required for supporting property browsing in Design view uses metadata attributes to inform Visual Studio .NET about how to handle the properties. Supporting statement completion and property browsing in HTML view requires creating a custom XSD schema that describes the types in your control. We'll discuss both techniques in the next sections.

Metadata attributes

Visual Studio .NET provides rich support for designing and modifying controls visually by using drag-and-drop techniques and tools, such as the Property browser, and related designers, such as the color picker. Support for these tools is provided by a series of metadata attributes that you can add to your control. These attributes tell the Visual Studio IDE whether to display any properties that your control exposes in the Properties browser, what type the properties are, and which designer should be used to set the properties' values.

To support editing of the AddRedirect property in the Property browser, we would add the following attributes before the Property procedure, as shown in the following code snippet:

[
Browsable(true),
Category("Behavior"),
Description("URL to which the page should redirect after 
   successful submission of a new Blog entry."),
Editor(typeof(System.Web.UI.Design.UrlEditor), typeof(UITypeEditor))
]
public string AddRedirect
{ // property procedure code }

These attribute declarations allow the property to be displayed in the Property browser, set the desired category for the property (when properties are sorted by category), provide a description of the property, and tell Visual Studio .NET to use the UrlEditor designer to edit the property's value.

TIP:   The attribute syntax shown in this section is for C#. In C#, attributes take the form:

[AttributeName(AttributeParams)]

In Visual Basic .NET, attributes are declared with the following syntax:

<AttributeName(AttributeParams)>

Visual Basic .NET requires that the attribute declaration appear on the same line as the member it's modifying, so it's usually a good idea to follow the attribute with a VB line continuation character to improve readability:

<AttributeName(AttributeParams)> _
Public Membername(  )

In both C# and VB, you can declare multiple attributes within a single set of [ ] or <> brackets by separating multiple attributes with commas.

In addition to setting attributes at the property level, you can set certain attributes at the class and assembly levels. For example, you can use the assembly-level attribute TagPrefix to specify the tag prefix to use for any controls contained in the assembly. Visual Studio .NET then inserts this tag prefix automatically when you add an instance of the control to a Web Forms page from the Visual Studio toolbox. The following code snippet shows the syntax for the TagPrefix attribute. This attribute should be placed within the class module that defines the control, but outside the class and namespace declarations.

[
assembly: TagPrefix("aspnetian", "aspnetian")
]
  
namespace aspnetian
{ // control classes, etc. }

ASP.NET in a Nutshell

Related Reading

ASP.NET in a Nutshell
By G. Andrew Duthie, Matthew MacDonald

To complete the integration of a control in the Visual Studio .NET environment, add the ToolBoxData attribute (which tells Visual Studio .NET your preferred tag name for controls inserted from the toolbox) to the class that implements the control:

[
ToolboxData("<{0}:Blog runat=server></{0}:Blog>")
]
public class Blog:Panel, INamingContainer
{ // control implementation }

Once compiled, the control will support automatic insertion of the @ Register directive, tag prefix, and tag name for the Blog control. To add the control to the Visual Studio .NET toolbox, follow these simple steps:

  1. In Design view, select the Web Forms tab of the Visual Studio .NET toolbox.
  2. Right-click anywhere in the tab and select Customize Toolbox.
  3. Select the .NET Framework Components tab, and then click Browse.
  4. Browse to the location of the compiled control assembly, select it, and click Open.
  5. Click OK.

Once the control has been added to the toolbox, you can add it to a Web Forms page by either double-clicking the control or dragging and dropping it from the toolbox onto the Web Forms page. In either case, Visual Studio .NET will automatically insert the correct @ Register directive, including setting the TagPrefix based on the assembly-level attribute, and will also create a set of tags for the control with the tag name specified in the ToolBoxData attribute.

Adding a designer

As written, the Blog control will not have any visible interface in the Design view of the Web Forms editor. This can make it more difficult to select the control on the page, and also may make it more difficult to understand what the control will look like at runtime. To correct this problem, we can add support for a designer that will render HTML at design time that approximates the look of the Blog control at runtime. Note that you can also create designers that completely reproduce the runtime output of a control, but doing so is more involved and beyond the scope of this book

All server control designers derive from the class System.Web.UI.Design.ControlDesigner, which exposes a number of methods you can override to provide design-time rendering for your control. Example 6-10 overrides the GetDesignTimeHtml method to return simple HTML. Note that the example shows the entire designer class for the Blog control, which you can add to the existing Blog.cs class file (making sure that the class declaration is within the namespace curly braces).

Example 6-10: BlogDesigner class

public class BlogDesigner:ControlDesigner
{
   public override string GetDesignTimeHtml(  ) 
   {
      return "<h1>Blog</h2><hr/><hr/>";
   }
}

To tie this designer into the Blog class, we use the Designer attribute, as shown in the following snippet. Note that this code also adds a Description attribute that describes what the control does.

[
Description("Simple Blog control. Supports display of Web log / news 
   items from an XML file."),
Designer(typeof(aspnetian.BlogDesigner)),
ToolboxData("<{0}:Blog runat=server></{0}:Blog>")
]
public class Blog:Panel, INamingContainer
{ // class implementation }

As you can see, the BlogDesigner class is extremely simple, but it adds a lot to the control's design-time appearance on a web page, as shown in Figure 6-4.

Figure 6-4. Adding design-time rendering

 

Example 6-11 shows the code for the Blog control, updated with attributes to enable design-time support for the control in Design view and the Property browser. Note that the example adds several using directives to import the namespaces needed to support the attributes and designer classes we've used. The example also adds an enumeration to be used for the value of the Mode property and a new property, SeparatorColor.

Example 6-11: Updated Blog.cs

using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
  
[
assembly: TagPrefix("aspnetian", "aspnetian")
]
  
namespace aspnetian
{
  
public enum BlogMode
{
   Add,
   Display
}
  
[
Description(@"Simple Blog control. Supports display of Web log / 
	news items from an XML file."),
Designer(typeof(aspnetian.BlogDesigner)),
ToolboxData("<{0}:Blog runat=server></{0}:Blog>")
]
public class Blog:Panel, INamingContainer
{
  
   protected DataSet BlogDS;
   protected TextBox TitleTB;
   protected TextBox BlogText;
  
   private string _addRedirect;
   private string _email;
   private BlogMode _mode;
   private Color _separatorColor = Color.Black;
  
   [
   Browsable(true),
   Category("Behavior"),
   Description("URL to which the page should redirect after 
      successful submission of a new Blog entry."),
   Editor(typeof(System.Web.UI.Design.UrlEditor), typeof(
   	  UITypeEditor))
   ]
   public string AddRedirect
   {
      get
      {
         return this._addRedirect;
      }
      set
      {
         this._addRedirect = value;
      }
   }
  
   [
   Browsable(true),
   Category("Behavior"),
   Description("Email address the control will use for 
   	  listing in new Blog entries.")
   ]
   public string Email
   {
      get
      {
         return this._email;
      }
      set
      {
         this._email = value;
      }
   }
  
   [
   Browsable(true),
   Category("Behavior"),
   Description("Controls whether existing Blogs are 
      displayed, or fields for creating a new Blog entry.")
   ]
   public BlogMode Mode
   {
      get
      {
         return this._mode;
      }
      set
      {
         this._mode = value;
      }
   }
  
   [
   Browsable(true),
   Category("Appearance"),
   Description("Controls the color of the line that separates Blog 
      entries when in display mode.")
   ]
   public Color SeparatorColor
   {
      get
      {
         return this._separatorColor;
      }
      set
      {
         this._separatorColor = value;
      }
   }
  
   protected override void OnInit(EventArgs e)
   {
      LoadData(  );
      base.OnInit(e);
   }
   
   protected override void CreateChildControls(  )
   {
      if (this._mode != BlogMode.Add)
      {
         DisplayBlogs(  );
      }
      else
      {
         NewBlog(  );
      }
   }
  
   protected void LoadData(  )
   {
      BlogDS = new DataSet(  );
  
      try
      {
         BlogDS.ReadXml(Page.Server.MapPath("Blog.xml"));
      }
      catch (FileNotFoundException fnfEx)
      {
         CreateBlankFile(  );
         LoadData(  );
      }
   }
  
   protected void DisplayBlogs(  )
   {
      DateTime BlogDate;
      DateTime CurrentDate = new DateTime(  );
  
      DataRowCollection BlogRows = BlogDS.Tables[0].Rows;
      foreach (DataRow BlogDR in BlogRows)
      {
         string BDate = BlogDR["date"].ToString(  );
         BlogDate = new DateTime(Convert.ToInt32(
         	BDate.Substring(4, 4)), 
            Convert.ToInt32(BDate.Substring(0, 2)),
            Convert.ToInt32(BDate.Substring(2, 2)));
  
         if (CurrentDate != BlogDate)
         {
            Label Date = new Label(  );
            Date.Text = BlogDate.ToLongDateString(  );
            Date.Font.Size = FontUnit.Large;
            Date.Font.Bold = true;
            this.Controls.Add(Date);
            this.Controls.Add(new LiteralControl("<br/><br/>"));
            CurrentDate = BlogDate;
         }
  
         HtmlAnchor Anchor = new HtmlAnchor(  );
         Anchor.Name = "#" + BlogDR["anchorID"].ToString(  );
         this.Controls.Add(Anchor);
  
         Label Title = new Label(  );
         Title.Text = BlogDR["title"].ToString(  );
         Title.Font.Size = FontUnit.Larger;
         Title.Font.Bold = true;
         this.Controls.Add(Title);
         
         this.Controls.Add(new LiteralControl("<p>"));
         LiteralControl BlogText = new LiteralControl("<div>" +
            BlogDR["text"].ToString(  ) + "</div>");
         this.Controls.Add(BlogText);
         this.Controls.Add(new LiteralControl("</p>"));
  
         HyperLink Email = new HyperLink(  );
         Email.NavigateUrl = "mailto:" + BlogDR["email"].ToString(  );
         Email.Text = "E-mail me";
         this.Controls.Add(Email);
  
         this.Controls.Add(new LiteralControl(" | "));
         HyperLink AnchorLink = new HyperLink(  );
         AnchorLink.NavigateUrl = Page.Request.Url.ToString(  ) 
         	+ "#" + BlogDR["anchorID"].ToString(  );
         AnchorLink.Text = "Link";
         this.Controls.Add(AnchorLink);
  
         this.Controls.Add(new LiteralControl("<hr color='" +
            _separatorColor.ToKnownColor(  ) + "' 
			width='100%'/><br/>"));
      }
   }
  
   protected void NewBlog(  )
   {
      Label Title = new Label(  );
      Title.Text = "Create New Blog";
      Title.Font.Size = FontUnit.Larger;
      Title.Font.Bold = true;
      this.Controls.Add(Title);
  
      this.Controls.Add(new LiteralControl("<br/><br/>"));
  
      Label TitleLabel = new Label(  );
      TitleLabel.Text = "Title: ";
      TitleLabel.Font.Bold = true;
      this.Controls.Add(TitleLabel);
      TitleTB = new TextBox(  );
      this.Controls.Add(TitleTB);
  
      this.Controls.Add(new LiteralControl("<br/>"));
      
      Label BlogTextLabel = new Label(  );
      BlogTextLabel.Text = "Text: ";
      BlogTextLabel.Font.Bold = true;
      this.Controls.Add(BlogTextLabel);
      BlogText = new TextBox(  );
      BlogText.TextMode = TextBoxMode.MultiLine;
      BlogText.Rows = 10;
      BlogText.Columns = 40;
      this.Controls.Add(BlogText);      
  
      this.Controls.Add(new LiteralControl("<br/>"));
  
      Button Submit = new Button(  );
      Submit.Text = "Submit";
      Submit.Click += new EventHandler(this.Submit_Click);
      this.Controls.Add(Submit);
   }
  
   protected void Submit_Click(object sender, EventArgs e)
   {
      EnsureChildControls(  );
      AddBlog(  );
   }
  
   protected void AddBlog(  )
   {
      DataRow NewBlogDR;
      NewBlogDR = BlogDS.Tables[0].NewRow(  );
      NewBlogDR["date"] = FormatDate(DateTime.Today);
      NewBlogDR["title"] = TitleTB.Text;
      NewBlogDR["text"] = BlogText.Text;
      NewBlogDR["anchorID"] = Guid.NewGuid().ToString(  );
      NewBlogDR["email"] = _email;
      BlogDS.Tables[0].Rows.InsertAt(NewBlogDR, 0);
      BlogDS.WriteXml(Page.Server.MapPath("Blog.xml"));
      Page.Response.Redirect(_addRedirect);
   }
  
   protected string FormatDate(DateTime dt)
   {
      string retString;
      retString = String.Format("{0:D2}", dt.Month);
      retString += String.Format("{0:D2}", dt.Day);
      retString += String.Format("{0:D2}", dt.Year);
      return retString;
   }
  
   public void CreateBlankFile(  )
   {
      // code to create new file...omitted to conserve space
   }
  
}
  
public class BlogDesigner:ControlDesigner
{
   public override string GetDesignTimeHtml(  ) 
   {
      return "<h1>Blog</h2><hr/><hr/>";
   }
}
  
}

Custom schemas and Visual Studio annotations

As much as the metadata attributes described in the previous section help provide support for the Blog control at design time, they're missing one important piece: IntelliSense support for adding tags and attributes in the HTML view of the Web Forms editor. For developers who are more comfortable working in HTML than in WYSIWYG style, this oversight is significant.

Since the HTML view of the Web Forms editor uses XSD schemas to determine which elements and attributes to make available in a Web Forms page, to correct the oversight, we need to implement an XSD schema that describes the Blog control and the attributes that it supports. Optionally, we can add annotations to the schema that tell Visual Studio .NET about the various elements and how we'd like them to behave.

Example 6-12 contains the portion of the XSD schema specific to the Blog control. The actual schema file (which is available in the sample code for the book) also contains type definitions for the Panel control from which the Blog control is derived, as well as other necessary attribute and type definitions. These definitions were copied from the asp.xsd schema file created for the built-in ASP.NET Server Controls.

WARNING:   You should never modify the asp.xsd schema file directly, but should copy any necessary type or attribute definitions to your custom schema file. While this may seem redundant, if you edit asp.xsd directly and a later installation or service pack for the .NET Framework overwrites this file, your custom schema entries would be lost.

Example 6-12: Blog.xsd

<?xml version="1.0" encoding="utf-8" ?> 
<xsd:schema targetNamespace="urn:http://www.aspnetian.com/schemas"
   elementFormDefault="qualified"
   xmlns="urn:http://www.aspnetian.com/schemas"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense"
   vs:friendlyname="Blog Control Schema"
   vs:ishtmlschema="false" 
   vs:iscasesensitive="false" 
   vs:requireattributequotes="true" >
   <xsd:annotation>
      <xsd:documentation>
         Blog Control schema.
      </xsd:documentation>
   </xsd:annotation>
  
   <xsd:element name="Blog" type="BlogDef" />
  
   <!-- <aspnetian:Blog> -->
   <xsd:complexType name="BlogDef">
      <!-- <aspnetian:Blog>-specific attributes -->
      <xsd:attribute name="AddRedirect" type="xsd:string"
         vs:builder="url"/>
      <xsd:attribute name="Email" type="xsd:string"/>
      <xsd:attribute name="Mode" type="BlogMode"/>
      <xsd:attribute name="SeparatorColor" type="xsd:string" 
         vs:builder="color"/>
      <!-- <asp:Panel>-specific attributes -->
      <xsd:attribute name="BackImageUrl" type="xsd:anyURI" />
      <xsd:attribute name="HorizontalAlign" type="HorizontalAlign" />
      <xsd:attribute name="Wrap" type="xsd:boolean" />
      <xsd:attribute name="Enabled" type="xsd:boolean" />
      <xsd:attribute name="BorderWidth" type="ui4" />
      <xsd:attribute name="BorderColor" type="xsd:string" 
         vs:builder="color" />
      <xsd:attribute name="BorderStyle" type="BorderStyle" />
      <xsd:attributeGroup ref="WebControlAttributes" />
   </xsd:complexType>
  
   <!-- DataTypes -->
   <xsd:simpleType name="BlogMode">
      <xsd:restriction base="xsd:string">
         <xsd:enumeration value="Add" />
         <xsd:enumeration value="Display" />
      </xsd:restriction>
   </xsd:simpleType>
</xsd:schema>

In Example 6-12, note the targetNamespace and xmlns attributes on the root schema element, which define the XML namespace for the control's schema. The value of the targetNamespace and xmlns attributes will also be used as an attribute in your Web Forms page to "wire up" the schema. The <xsd:element> tag defines the root Blog element. The <xsd:complexType> tag defines the attributes for the Blog element, which includes the web control attributes referenced by the <xsd:attributeGroup> tag. Finally, the <xsd:simpleType> tag defines the enumeration for the BlogMode type used as one of the attributes for the Blog element.

Note that Example 6-12 uses the vs:builder annotation to tell Visual Studio .NET to use the Url builder for the AddRedirect attribute and the Color builder for the SeparatorColor attribute. The vs:builder annotation is one of many annotations available to modify schemas. The most commonly used annotations are listed in Table 6-1.

Table 6-1: Common Visual Studio .NET annotations

Annotation

Purpose

Valid values

vs:absolutepositioning

Used at the root <schema> element to determine whether Visual Studio may insert style attributes for positioning.

true/false

vs:blockformatted

Indicates whether leading whitespace may be added to the element during automatic formatting.

true/false

vs:builder

Specifies the builder to be used for editing the related property's value.

color, style, or url

vs:deprecated

Allows a related property to be marked as `deprecated', which prevents it from showing up in the Properties browser and in statement completion.

true/false

vs:empty

Used at the element level to indicate that Visual Studio .NET should use single tag syntax for the related tag (no end tag).

true/false

vs:friendlyname

Used at the root level to provide a display name for the schema.

 

vs:iscasesensitive

Used at the root level and specifies whether Visual Studio .NET will treat the related tags in a case-sensitive manner.

true/false

vs:ishtmlschema

Used at the root level and specifies whether the schema is an HTML document schema.

true/false

vs:nonbrowseable

Used at the attribute level and specifies that the attribute should not appear in statement completion.

true/false

vs:readonly

Used at the attribute level and specifies that the attribute may not be modified in the Properties window.

true/false

vs:requireattributequotes

Used at the root level and specifies that the attribute values must have quotes.

true/false

Once you've built your XSD schema, save it to the same location as the asp.xsd file (which defaults to C:\ProgramFiles\MicrosoftVisualStudio.NET\Common7\Packages\schemas\xml).

To allow Visual Studio .NET to read your custom schema, you'll need to add an xmlns attribute to the <body> tag of the page in which you wish to use the schema, as shown in the following snippet:

<body xmlns:aspnetian="urn:http://www.aspnetian.com/schemas">

Notice that this code uses the aspnetian prefix with the xmlns attribute to specify that the schema is for controls prefixed with the aspnetian tag prefix. This recall is set up by the TagPrefix attribute (described in the previous section on "Metadata attributes"). The value of the xmlns attribute should be the same as the targetNamespace attribute defined at the root of the schema.

Once you've wired up your schema via the xmlns attribute, you should be able to type an opening < character and have the Blog control appear as one of the options for statement completion, as shown in Figure 6-5.

Figure 6-5. Statement completion in HTML view

 

Example 6-13 shows the code for a page that uses the Blog control from Visual Studio .NET, including the xmlns attribute added to the <body> element.

Example 6-13: BlogClient_VS.aspx

<%@ Register TagPrefix="aspnetian" Namespace="aspnetian" 
   Assembly="Blog" %>
<%@ Page Language="vb" AutoEventWireup="True" Debug="True"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
   <head>
      <title>Blog Client</title>
      <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">
      <script runat="server">
         Sub Page_Load(  )
            If Request.QueryString("mode") = "add" Then
               Blog1.Mode = BlogMode.Add
               Link1.Visible = False
               Link2.Visible = False
            Else
               Blog1.Mode = BlogMode.Display
               Link1.Visible = True
               Link2.Visible = True
            End If
         End Sub
      </script>
   </head>
   <body xmlns:aspnetian="urn:http://www.aspnetian.com/schemas">
      <form id="Form1" method="post" runat="server">
         <p><asp:hyperlink id="Link1" runat="server" 
               navigateurl="WebForm1.aspx?mode=add">
               Add Blog
            </asp:hyperlink></p>
         <p><aspnetian:blog id="Blog1" addredirect="WebForm1.aspx" 
               email="andrew@aspnetian.com" runat="server" >
            </aspnetian:blog></p>
         <p><asp:hyperlink id="Link2" runat="server" 
               navigateurl="WebForm1.aspx?mode=add">
               Add Blog
            </asp:hyperlink></p>
      </form>
   </body>
</html>

Notice that Example 6-13 provides support for both displaying and adding blog entries from within the same page; this is done by omitting the Mode property in the tag that defines the control and setting the Mode programmatically (based on whether or not the page request was the result of the user clicking one of the "Add Blog" Hyperlink controls added to the page).

In This Series

User Controls and Custom Server Controls, Part 4
In this final installment in a series of excerpts from ASP.NET in a Nutshell, learn how to share ASP.NET controls across applications.

User Controls and Custom Server Controls, Part 2
In Part 2 in this series of excerpts from ASP.NET in a Nutshell, learn ASP.NET custom server controls.

User Controls and Custom Server Controls, Part 1
In part one from this series of book excerpts from ASP.NET in a Nutshell, get an overview on ASP.NET controls, and learn about ASP.NET user controls.

When the page is loaded for the first time, it will be in Display mode. Clicking one of the hyperlinks will request the page with the mode QueryString element set to add, which will cause the page to render in Add mode.

Adding Client Script

Sometimes you may want to use client-side script in your ASP.NET pages, either with controls or independent of them. In classic ASP, it was possible to write client script to the browser using Response.Write. However, this could get very messy-- particularly if you needed to write the same set of code for use with more than one form element.

The ASP.NET Page class provides several methods for sending client script to the browser that make this process simpler and more reliable.

These methods include:

RegisterClientScriptBlock
Renders a string containing the specified client script to the browser.

RegisterHiddenField
Adds an <input> element whose type is set to hidden.

IsClientScriptBlockRegistered
Allows you to test whether a given named script block has been already registered by another control to avoid redundancy.

You might use these methods to pop up a message box on the client with the number of Blogs that currently exist in the XML file. To accomplish this, add the following snippet to the DisplayBlogs method of the Blog control:

Page.RegisterClientScriptBlock("Blog", "<script>alert('There are now " +
   BlogRows.Count + " Blogs!');</script>");

Then, if any other controls need to use the same script, call IsClientScriptBlockRegistered, passing it the name of the script shown above, Blog, to determine whether to call RegisterClientScriptBlock again. In this way, a single client-side script block may be shared among multiple controls.

In the final installment, learn about sharing controls across applications

.

Matthew MacDonald is a developer, author, and educator in all things Visual Basic and .NET. He's worked with Visual Basic and ASP since their initial versions, and written over a dozen books on the subject, including The Book of VB .NET (No Starch Press) and Visual Basic 2005: A Developer's Notebook (O'Reilly). His web site is http://www.prosetech.com/.

G. Andrew Duthie is the founder and principal of Graymad Enterprises, Inc., which provides training and consulting in Microsoft Web development technologies.

ASP.NET in a Nutshell

Related Reading

ASP.NET in a Nutshell
By G. Andrew Duthie, Matthew MacDonald

Return to the .NET DevCenter

Copyright © 2009 O'Reilly Media, Inc.