CHAPTER 36 Building Custom Controls View State and Control State The standard ASP.NET controls retain the values of their properties across postbacks.. The ASP.NET Framework takes advant
Trang 1CHAPTER 36 Building Custom Controls
EnsureChildControls();
txtPassword.Text = value;
}
}
protected override void CreateChildControls()
{
txtUserName = new TextBox();
txtUserName.ID = “txtUserName”;
this.Controls.Add(txtUserName);
txtPassword = new TextBox();
txtPassword.ID = “txtPassword”;
txtPassword.TextMode = TextBoxMode.Password;
this.Controls.Add(txtPassword);
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.AddStyleAttribute(“float”, “left”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, “3px”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddAttribute(HtmlTextWriterAttribute.For, txtUserName.ClientID);
writer.RenderBeginTag(HtmlTextWriterTag.Label);
writer.Write(“User Name:”);
writer.RenderEndTag();
writer.RenderEndTag();
writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, “3px”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddAttribute(HtmlTextWriterAttribute.For, txtPassword.ClientID);
writer.RenderBeginTag(HtmlTextWriterTag.Label);
writer.Write(“Password:”);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.AddStyleAttribute(“float”, “left”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, “3px”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
txtUserName.RenderControl(writer);
writer.RenderEndTag();
Trang 2writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, “3px”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
txtPassword.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.Write(“<br style=’clear:left’ />”);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
}
The control in Listing 36.11 works quite nicely in all recent browsers (Internet Explorer 6,
Firefox, Opera 8) without requiring an HTML table for layout (see Figure 36.6)
FIGURE 36.6 Performing CSS layout
Trang 3CHAPTER 36 Building Custom Controls
View State and Control State
The standard ASP.NET controls retain the values of their properties across postbacks For
example, if you change the text displayed by a Label control, the Label control continues
to display the new text even if you repeatedly post the page containing the Label control
back to the server
The ASP.NET Framework takes advantage of a hidden form field named VIEWSTATE to
preserve the state of control properties across postbacks If you want your controls to
preserve the values of their properties, you need to add the values of your control
proper-ties to this hidden form field using the appropriate APIs—never access this hidden form
field directly
The ASP.NET Framework supports two methods of preserving values across postbacks You
can take advantage of either View State or Control State
Supporting View State
You can use the ViewState property of the Control or Page class to add values to View
State The ViewState property exposes a dictionary of key and value pairs For example,
the following statement adds the string Hello World! to View State:
ViewState[“message”] = “Hello World!”
Technically, you can add an instance of any serializable class to View State In practice,
however, you should add only simple values to View State, such as Strings, DateTimes,
and Integers Remember that anything that you add to View State must be added to the
hidden VIEWSTATE form field If this field gets too big, it can have a significant impact
on your page’s performance
The control in Listing 36.12 has two properties: Text and ViewStateText The first
prop-erty does not use View State, and the second propprop-erty does use View State The value of
the ViewStateText property is preserved across postbacks automatically
LISTING 36.12 ViewStateControl.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
public class ViewStateControl : WebControl
{
private string _text;
public string Text
Trang 4{
get { return _text; }
set { _text = value; }
}
public string ViewStateText
{
get
{
if (ViewState[“ViewStateText”] == null) return String.Empty;
else return (string)ViewState[“ViewStateText”];
}
set { ViewState[“ViewStateText”] = value; }
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write(“Text: “ + Text);
writer.WriteBreak();
writer.Write(“ViewStateText: “ + ViewStateText);
writer.WriteBreak();
}
}
}
The ViewStateText property uses the Control’s ViewState collection to preserve whatever
value is assigned to the ViewStateText property across postbacks When you add a value
to the ViewState collection, the value is stuffed into the hidden VIEWSTATE form field
automatically
WARNING
View State is loaded after the Page InitComplete event, and View State is saved after
the Page PreRenderComplete event This means that you should not attempt to
retrieve a value from View State before or during the InitComplete event You also
should not attempt to add a value to View State after the PreRenderComplete event
The page in Listing 36.13 includes ViewStateControl The text Hello World! is assigned
to both control properties in the Page_Load() handler However, if you post the page back
to itself by clicking the button, only the value of the ViewStateText property is preserved
across postbacks
Trang 5CHAPTER 36 Building Custom Controls
LISTING 36.13 ShowViewState.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”>
<script runat=”server”>
void Page_Load()
{
if (!Page.IsPostBack)
{
ViewStateControl1.Text = “Hello World!”;
ViewStateControl1.ViewStateText = “Hello World!”;
}
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>Show View State</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<custom:ViewStateControl
id=”ViewStateControl1”
Runat=”server” />
<asp:Button
id=”btnSubmit”
Text=”Submit”
Runat=”server” />
</div>
</form>
</body>
</html>
Trang 6Supporting Control State
The ASP.NET Framework includes a feature named Control State, which is similar to View
State Just like View State, any values that you add to Control State are preserved in the
hidden VIEWSTATE form field However, unlike View State, Control State cannot be
disabled Control State is intended to be used only for storing crucial information across
postbacks
Control State was introduced to address a problem that developers encountered in the first
version of ASP.NET Framework You can disable View State for any control by assigning the
value False to a control’s EnableViewState property Often, this is a good idea for
perfor-mance reasons; however, disabling View State also made several controls nonfunctional
For example, by default a GridView control retains the values of all the records that it
displays in View State If you display 500 database records with a GridView control, by
default all 500 records are stuffed into the hidden VIEWSTATE form field To improve
performance, you might want to disable View State for the GridView
However, a GridView uses the VIEWSTATE form field to remember crucial information
required for the proper functioning of the control, such as the current page number and
the currently selected row You don’t want the GridView to forget this critical information
even when View State is disabled
The concept of Control State was introduced to enable you to save critical information in
the hidden VIEWSTATE form field even when View State is disabled Microsoft makes it
slightly more difficult to use Control State because they don’t want you to overuse this
feature You should use it only when storing super critical information
For example, the control in Listing 36.14 includes two properties named ViewStateText
and ControlStateText View State preserves the value of the first property, and Control
State preserves the value of the second property
LISTING 36.14 ControlStateControl.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
public class ControlStateControl : WebControl
{
private string _controlStateText;
public string ViewStateText
{
Trang 7CHAPTER 36 Building Custom Controls
get
{
if (ViewState[“ViewStateText”] == null) return String.Empty;
else return (string)ViewState[“ViewStateText”];
}
set { ViewState[“ViewStateText”] = value; }
}
public string ControlStateText
{
get { return _controlStateText; }
set { _controlStateText = value; }
}
protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override object SaveControlState()
{
return _controlStateText;
}
protected override void LoadControlState(object savedState)
{
_controlStateText = (string)savedState;
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write(“ViewStateText: “ + ViewStateText);
writer.WriteBreak();
writer.Write(“ControlStateText: “ + ControlStateText);
writer.WriteBreak();
}
}
}
Trang 8The control in Listing 36.14 overrides the base Control class’s OnInit(),
SaveControlState(), and LoadControlState() methods In the OnInit() method, the
RegisterRequiresControlState() method is called to indicate that the control needs to
take advantage of Control State
The SaveControlState() and LoadControlState() methods are responsible for saving and
loading the Control State Control State is saved as an object The object is serialized by
ASP.NET Framework into the hidden VIEWSTATE form field automatically
The page in Listing 36.15 illustrates the difference between View State and Control State In
the Page_Load() handler, the value Hello World! is assigned to both properties of the
ControlStateControl The control has View State disabled; however, if you click the button
and post the page back to itself, the value of the ControlStateText property is not lost
LISTING 36.15 ShowControlState.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”>
<script runat=”server”>
void Page_Load()
{
if (!Page.IsPostBack)
{
ControlStateControl1.ViewStateText = “Hello World!”;
ControlStateControl1.ControlStateText = “Hello World!”;
}
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show Control State</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<custom:ControlStateControl
id=”ControlStateControl1”
EnableViewState=”false”
Runat=”server” />
<asp:Button
Trang 9CHAPTER 36 Building Custom Controls
id=”btnSubmit”
Text=”Submit”
Runat=”server” />
</div>
</form>
</body>
</html>
Processing Postback Data and Events
The ASP.NET Framework is built around web forms and controls pass information from
the browser to the server by submitting a form to the server This process of posting a
form back to the server is called a postback.
When an ASP.NET page processes a form that has been posted back to the server, two
types of information can be passed to the controls in the page First, if a control initiates a
postback, a server-side event can be raised when the form is posted to the server For
example, if you click a Button control, a Click event is raised on the server when the form
containing the Button is posted back to the server This event is called a postback event.
Second, the form data contained in the web form can be passed to a control For example,
when you submit a form that contains a TextBox control, the form data is passed to the
TextBox control when the web form is submitted to the server This form data is called the
postback data.
When building a custom control, you might need to process either postback data or a
postback event In this section, you learn how to implement the required control
inter-faces for processing postbacks
Handling Postback Data
If your control needs to process form data submitted to the server, you need to implement
the IPostbackDataHandler interface This interface includes the following two methods:
LoadPostData()—Receives the form fields posted from the browser
RaisePostDataChangedEvent()—Enables you to raise an event indicating that the
value of a form field has been changed
For example, the control in Listing 36.16 is a simple TextBox control that implements the
IPostbackDataHandler interface to preserve the state of an input field across postbacks
Trang 10LISTING 36.16 CustomTextBox.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
public class CustomTextBox : WebControl, IPostBackDataHandler
{
public event EventHandler TextChanged;
public string Text
{
get
{
if (ViewState[“Text”] == null) return String.Empty;
else return (string)ViewState[“Text”];
}
set { ViewState[“Text”] = value; }
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Type, “text”);
writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
base.AddAttributesToRender(writer);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Input;
}
}
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
if (postCollection[postDataKey] != Text)
{