Handling Data After Post Back
Introduction
In the last two lessons you were introduced with rendering of custom
controls. Often your custom controls consist of input controls that allow users
to edit data. The new data entered by the user must be persisted across post
backs. In this lesson you will learn just that.
IPostBackDataHandler interface
In order to handle data after page post back the custom control class must
implement IPostBackDataHandler interface. The IPostBackDataHandler interface
defines the following two methods:
- LoadPostData: The LoadPostData method allows you to
read posted data. The method receives two parameters viz. postDataKey and
postCollection. The postDataKey is the ID of the custom control and
postCollection contains all the posted data. You can retrieve posted data
for your custom control by specifying the postDataKey. The LoadPostData
method should return true if the data inside the control has been changed
else it should return false.
- RaisePostDataChangedEvent: The
PaisePostDataChangedEvent method is intended to raise an event that
indicates that the control data has been changed. This method is raised only
if LoadPostData method returns true.
Address Control
In order to understand how data can be accessed after page post back you are
going to build an Address custom control. The control will render three
textboxes to enter street address, city and postal code respectively. The
entered data must be preserved across post backs.
Create a new web site and add a class named AddressControl to its App_Code
folder. The following markup shows the control class declaration:
namespace BinaryIntellect.UI
{
public class AddressControl : WebControl,
IPostBackDataHandler
{
...
}
}
The above code defines AddressControl class inside BinaryIntellect.UI
namespace. The AddressControl class inherits from WebControl and also implements
IPostBackDataHandler interface.
Then add three string properties namely Street, City and Country as shown
below:
public string Street
{
get
{
return ViewState["street"] as string;
}
set
{
ViewState["street"] = value;
}
}
public string City
{
get
{
return ViewState["city"] as string;
}
set
{
ViewState["city"] = value;
}
}
public string PostalCode
{
get
{
return ViewState["postalcode"] as string;
}
set
{
ViewState["postalcode"] = value;
}
}
The properties Street, City and PostalCode store their values directly in the
ViewState. Notice the use of "as string" in the above code. This way an empty
string is returned if the ViewState value is null.
The AddressControl class raises AddressChanged event if the address has
changed since the last rendering. The AddressChanged event looks as shown below:
public event EventHandler AddressChanged;
In order to display three textboxes for entering the address information you
need to override Render() method of the base class.
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.WriteBeginTag("INPUT");
writer.WriteAttribute("type", "text");
writer.WriteAttribute("name", this.UniqueID);
writer.WriteAttribute("value", Street);
writer.Write("/>");
writer.WriteFullBeginTag("br");
writer.WriteBeginTag("INPUT");
writer.WriteAttribute("type", "text");
writer.WriteAttribute("name", this.UniqueID +"city");
writer.WriteAttribute("value", City);
writer.Write("/>");
writer.WriteFullBeginTag("br");
writer.WriteBeginTag("INPUT");
writer.WriteAttribute("type", "text");
writer.WriteAttribute("name", this.UniqueID + "postalcode");
writer.WriteAttribute("value", PostalCode);
writer.Write("/>");
writer.WriteFullBeginTag("br");
}
The Render() method simply emits three <INPUT> tags with type as Text. Notice
the name attribute of each tag carefully. For the first <INPUT> you set the name
attribute to UniqueID property. The other two textboxes simply append city and
postalcode to the UniqueID property. This way we can easily retrieve their
values later. The value attribute simply contains the value of Street, City and
PostalCode properties respectively.
Now its time to implement LoadPostData() method.
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
string street = postCollection[postDataKey];
string city = postCollection[postDataKey + "city"];
string postalcode = postCollection[postDataKey + "postalcode"];
if (street == Street && city == City && postalcode == PostalCode)
{
return false;
}
else
{
Street = street;
City = city;
PostalCode = postalcode;
return true;
}
}
The LoadPostData() method accepts two parameters viz. postDataKey and
postCollection. The values after the post back can be retrieved using this
name-value collection. Notice how the code retrieves city and postal code by
appending "city" and "postalcode" to the postDataKey. The code then checks if
any of the values are changed. If the values are changed then it returns true
otherwise it returns false.
The RaisePostDataChangeEvent() method is shown next:
public void RaisePostDataChangedEvent()
{
if (AddressChanged != null)
{
AddressChanged(this, EventArgs.Empty);
}
}
Here you need to check if there are any subscribers for the AddressChanged
event. If so you raise the AddressChanged event.
This completes the AddressControl. In order to see AddressControl in action
open the default web form and register the AddressControl with the page
framework as shown below:
<%@ Register Namespace="BinaryIntellect.UI"
TagPrefix="mycontrols" %>
Also, create one instance of the AddressControl as follows:
<mycontrols:AddressControl runat="server" id="ctrl1"
OnAddressChanged="MyHandler" />
The AddressChanged event is handled by MyHandler method from the web form
code behind. The MyHandler method looks like this:
protected void MyHandler(object sender, EventArgs e)
{
AddressControl ac = (AddressControl)sender;
Label1.Text = "Your address :" + ac.Street + ","
+ ac.City + "," + ac.PostalCode;
}
The MyHandler() method simply displays the entered address in a Label
control.
That's it! If you run the default web form then it should resemble the
following screen shot.