Using the ParseChildren Attribute When building a control that contains a collection of child controls, you need to be aware of a ParseChildren attribute, which determines how the conten
Trang 1You specify advanced postback options by taking advantage of the PostBackOptions class
This class has the following properties:
ActionUrl—Enables you to specify the page where form data is posted
Argument—Enables you to specify a postback argument
AutoPostBack—Enables you to add JavaScript necessary for implementing an
AutoPostBack event
ClientSubmit—Enables you to initiate the postback through client-side script
PerformValidation—Enables you to specify whether validation is performed (set by
the CausesValidation property)
RequiresJavaScriptProtocol—Enables you to generate the JavaScript: prefix
TargetControl—Enables you to specify the control responsible for initiating the
postback
TrackFocus—Enables you to scroll the page back to its current position and return
focus to the control after a postback
ValidationGroup—Enables you to specify the validation group associated with the
control
Imagine that you need to create a form that enables users to place a product order
However, imagine that you want to create an advanced options check box When
someone clicks the advanced options check box, the current form data is submitted to a
new page that includes a more complex form
The AdvancedCheckBox control in Listing 36.22 supports cross-page posts When you click
the check box, the form data is submitted to the page indicated by its PostBackUrl
property
NOTE
Cross-page posts are covered during the discussion of Button controls in Chapter 2,
“Using the Standard Controls.”
LISTING 36.22 AdvancedCheckBox.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
public class AdvancedCheckBox : WebControl
{
Trang 2private string _Text;
private string _PostBackUrl;
public string Text
{
get { return _Text; }
set { _Text = value; }
}
public string PostBackUrl
{
get { return _PostBackUrl; }
set { _PostBackUrl = value; }
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
PostBackOptions options = new PostBackOptions(this);
options.ActionUrl = _PostBackUrl;
string eRef = Page.ClientScript.GetPostBackEventReference(options);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, eRef);
writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Type, “checkbox”);
base.AddAttributesToRender(writer);
}
protected override void RenderContents(HtmlTextWriter writer)
{
if (!String.IsNullOrEmpty(_Text))
{
writer.AddAttribute(HtmlTextWriterAttribute.For, this.ClientID);
writer.RenderBeginTag(HtmlTextWriterTag.Label);
writer.Write(_Text);
writer.RenderEndTag();
}
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Input;
Trang 3}
}
}
}
In the AddAttributesToRender() method in Listing 36.22, an instance of the
PostBackOptions class is created The ActionUrl property is modified to support
cross-page posts The instance of the PostBackOptions class is passed to the
GetPostBackEventReference() method to generate the JavaScript for initiating the
postback
The page in Listing 36.23 illustrates how you can use the AdvancedCheckBox control to
submit form data to a new page when you click the check box (see Figure 36.10) The
AdvancedCheckBox control’s PostBackUrl property is set to the value
ShowAdvancedOptions.aspx When you click the check box, the form data is posted to
this page
FIGURE 36.10 Using the AdvancedCheckBox control
LISTING 36.23 ShowAdvancedCheckBox.aspx
<%@ Page Language=”C#” %>
<%@ Register TagPrefix=”custom” Namespace=”myControls” %>
<!DOCTYPE html PUBLIC
“-//W3C//DTD XHTML 1.0 Transitional//EN”
Trang 4“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<script runat=”server”>
public string ProductName
{
get { return txtProductName.Text; }
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show AdvancedCheckBox</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:Label
id=”lblProductName”
Text=”Product Name:”
AssociatedControlID=”txtProductName”
Runat=”server” />
<asp:TextBox
id=”txtProductName”
Runat=”server” />
<br /><br />
<custom:AdvancedCheckBox
id=”AdvancedCheckBox1”
Text=”Advanced Options”
PostBackUrl=”AdvancedOptions.aspx”
Runat=”server” />
</div>
</form>
</body>
</html>
Trang 5Working with Control Property Collections
When you build more complex controls, you often need to represent a collection of items
For example, the standard ASP.NET DropDownList control contains one or more ListItem
controls that represent individual options in the DropDownList The GridView control can
contain one or more DataBoundField controls that represent particular columns to display
In this section, we build several controls that represent a collection of items We build
multiple content rotator controls that randomly display HTML content, and a server-side
tab control that renders a tabbed view of content
Using the ParseChildren Attribute
When building a control that contains a collection of child controls, you need to be aware
of a ParseChildren attribute, which determines how the content contained in a control is
parsed
When the ParseChildren attribute has the value True, content contained in the control is
parsed as properties of the containing control If the control contains child controls, the
child controls are parsed as properties of the containing control (The attribute should
have been named the ParseChildrenAsProperties attribute.)
When the ParseChildren attribute has the value False, no attempt is made to parse a
control’s child controls as properties The content contained in the control is left alone
The default value of the ParseChildren attribute is False However, the WebControl class
overrides this default value and sets the ParseChildren attribute to the value to True
Therefore, you should assume that ParseChildren is False when used with a control
that inherits directly from the System.Web.UI.Control class, but assume that
ParseChildren is True when used with a control that inherits from the
System.Web.UI.WebControls.WebControl class
Imagine, for example, that you need to create a content rotator control that randomly
displays content in a page There are two ways of creating this control, depending on
whether ParseChildren has the value True or False
The control in Listing 36.24 illustrates how you can create a content rotator control when
ParseChildren has the value False
LISTING 36.24 ContentRotator.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
Trang 6[ParseChildren(false)]
public class ContentRotator : WebControl
{
protected override void AddParsedSubObject(object obj)
{
if (obj is Content)
base.AddParsedSubObject(obj);
}
protected override void RenderContents(HtmlTextWriter writer)
{
Random rnd = new Random();
int index = rnd.Next(this.Controls.Count);
this.Controls[index].RenderControl(writer);
}
}
public class Content : Control
{
}
}
The file in Listing 36.24 actually contains two controls: ContentRotator and a Content
The ContentRotator control randomly selects a single Content control from its child
controls and renders the Content control to the browser This all happens in the control’s
RenderContents() method
The ParseChildren attribute has the value False in Listing 36.24 If you neglected to add
this attribute, the Content controls would be parsed as properties of the ContentRotator
control, and you would get an exception
NOTE
The AddParsedSubObject() method is discussed in the next section
The page in Listing 36.25 illustrates how you can use the ContentRotator and Content
controls (see Figure 36.11)
Trang 7LISTING 36.25 ShowContentRotator.aspx
<%@ Page Language=”C#” %>
<%@ Register TagPrefix=”custom” Namespace=”myControls” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
➥“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show ContentRotator</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<custom:ContentRotator
id=”ContentRotator1”
Runat=”server”>
<custom:Content
id=”Content1”
Runat=”server”>
First Content Item
</custom:Content>
<custom:Content
FIGURE 36.11 Randomly displaying content with the ContentRotator control
Trang 8id=”Content2”
Runat=”server”>
Second Content Item
<asp:Calendar
id=”Calendar1”
Runat=”server” />
</custom:Content>
<custom:Content
id=”Content3”
Runat=”server”>
Third Content Item
</custom:Content>
</custom:ContentRotator>
</div>
</form>
</body>
</html>
If ParseChildren is not set to the value False, you need to add a property to your control
that corresponds to the child controls contained in the control For example, the control
in Listing 36.26 includes an Items property that represents the Item controls contained in
the control
LISTING 36.26 ItemRotator.cs
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace myControls
{
[ParseChildren(true, “Items”)]
public class ItemRotator : CompositeControl
{
private ArrayList _items = new ArrayList();
[Browsable(false)]
public ArrayList Items
{
get { return _items; }
}
Trang 9protected override void CreateChildControls()
{
Random rnd = new Random();
int index = rnd.Next(_items.Count);
Control item = (Control)_items[index];
this.Controls.Add(item);
}
}
public class Item : Control
{
}
}
In Listing 36.26, the second value passed to the ParseChildren attribute is the name of a
control property The contents of the ItemRotator are parsed as items of the collection
represented by the specified property
Unlike the ContentRotator control, the controls contained in the ItemRotator control are
not automatically parsed into child controls After the CreateChildControls() method
executes, the ItemRotator control contains only one child control (the randomly selected
Item control)
The page in Listing 36.27 illustrates how you can use the ItemRotator control to
randomly display page content
LISTING 36.27 ShowItemRotator.aspx
<%@ Page Language=”C#” Trace=”true” %>
<%@ Register TagPrefix=”custom” Namespace=”myControls” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
➥“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show ItemRotator</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<custom:ItemRotator
id=”ItemRotator1”
Runat=”server”>
<custom:item ID=”Item1” runat=”server”>
First Item
Trang 10</custom:item>
<custom:item ID=”Item2” runat=”server”>
Second Item
<asp:Calendar
id=”Calendar1”
Runat=”server” />
</custom:item>
<custom:item ID=”Item3” runat=”server”>
Third Item
</custom:item>
</custom:ItemRotator>
</div>
</form>
</body>
</html>
There is no requirement that the contents of a control must be parsed as controls When
building a control that represents a collection of items, you can also represent the items as
objects For example, the ImageRotator control in Listing 36.28 contains ImageItem
objects The ImageItem class does not represent a control
LISTING 36.28 ImageRotator.cs
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace myControls
{
[ParseChildren(true, “ImageItems”)]
public class ImageRotator : WebControl
{
private ArrayList _imageItems = new ArrayList();
public ArrayList ImageItems
{
get
{
return _imageItems;
}
}