Listing 26-31: Handling postback events in a server control VB Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Text Imports System.Web Impo
Trang 1Now that you can create a postback, you may want to add events to your control that execute
dur-ing the page postback To raise server-side events from a client-side object, you implement the
Sys-tem.Web.IPostBackEventHandler interface Listing 26-31 shows how to do this for a button control You also create a server-side Click event you can handle when the page posts back
Listing 26-31: Handling postback events in a server control
VB
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text")> _
<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _
Public Class ServerControl1
Inherits System.Web.UI.WebControls.WebControl
Implements IPostBackEventHandler
’ Code removed for clarity
Public Event Click()
Public Sub OnClick(ByVal args As EventArgs)
RaiseEvent Click()
End Sub
Public Sub RaisePostBackEvent(ByVal eventArgument As String) _
Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
OnClick(EventArgs.Empty)
End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : WebControl, IPostBackEventHandler
{
// Code removed for clarity
#region IPostBackEventHandler Members
1241
Trang 2public event EventHandler Click;
public virtual void OnClick(EventArgs e) {
if (Click != null) {
Click(this,e);
} } public void RaisePostBackEvent(string eventArgument) {
OnClick(EventArgs.Empty);
}
#endregion }
}
Now, when the user clicks the button and the page posts back, the server-side Click event fires, allowing
you to add server-side handling code to the event
Handling PostBack Data
Now that you have learned how to store data in ViewState and add postback capabilities to a control,
look at how you can enable the control to interact with data the user enters into one of its form fields
When a page is posted back to the server by ASP.NET, all the form data is also posted to the server If the
control can interact with data that is passed with a page, you can store the information in ViewState and
complete the illusion of a stateful application
To interact with postback data, your control must be able to access the data To do this, it implements
the System.Web.IPostBackDataHandler interface This interface allows your control to examine the form
data that is passed back to the server during the postback
The IPostBackDataHandler interface requires that you implement two methods:LoadPostData and
RaisePostBackDataChangedEvent TheLoadPostDatamethod is called for all server controls on the page
that have postback data If a control does not have any postback data, the method is not called; however,
you can explicitly ask for the method to be called by using theRegisterRequiresPostBackmethod
Listing 26-32 shows how you implement the IPostBackDataHandler interface method in a text box
Listing 26-32: Accessing Postback data in a server control
VB
Imports System
Imports Sustem.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text")> _
1242
Trang 3<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _
Public Class ServerControl1
Inherits SystemWebControl
Implements IPostBackEventHandler, IPostBackDataHandler
’ Code removed for clarity
Public Function LoadPostData(ByVal postDataKey As String, _
ByVal postCollection As _
System.Collections.Specialized.NameValueCollection) _
As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
Me.Text = postCollection(postDataKey)
Return False
End Function
Public Sub RaisePostDataChangedEvent() _
Implements System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent
End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : WebControl,
IPostBackEventHandler, IPostBackDataHandler
{
// Code removed for clarity
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
this.Text = postCollection[postDataKey];
return false;
}
public void RaisePostDataChangedEvent()
{
}
}
}
1243
Trang 4As you can see, theLoadPostDatamethod passes any form data submitted to the method as a name
value collection that the control can access ThepostDataKeyparameter allows the control to access
the postback data item specific to it You use these parameters to save text to theTextproperty of the
TextBox control If you remember the earlier ViewState example, theTextproperty saves the new value
to ViewState; when the page renders, the TextBox value automatically repopulates
In addition to the input parameters, theLoadPostDatamethod also returns a Boolean value This
value indicates whether theRaisePostBackDataChangedEventmethod is also called after the
LoadPostDatamethod completes execution In the sample, it returnsfalsebecause no events exist,
but if you create aTextChangedevent to indicate the Textbox text has changed, you raise that event in
theRaisePostDataChangedEventmethod
Composite Controls
So far, in looking at Server controls, you have concentrated on emitting a single HTML control; but
this can be fairly limiting Creating extremely powerful controls often requires that you nest several
HTML elements together ASP.NET allows you to easily create controls that serve as a container for other
controls These types of controls are called composite controls.
To demonstrate how easy creating a composite control can be, try to change an existing control into a
composite control Listing 26-33 shows how you can do this
Listing 26-33: Creating a composite control
VB
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text")> _
<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _
Public Class ServerControl1
Inherits System.Web.UI.WebControls.CompositeControl
Protected textbox As TextBox
Protected Overrides Sub CreateChildControls()
Me.Controls.Add(textbox) End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
1244
Trang 5using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : CompositeControl
{
protected TextBox textbox = new TextBox();
protected override void CreateChildControls() {
this.Controls.Add(textbox);
} }
}
A number of things in this listing are important First, notice that the control class is now inheriting
fromCompositeControl, rather thanWebControl Deriving fromCompositeControlgives you a few
extra features specific to this type of control
Second, notice that noRendermethod appears in this code Instead, you simply create an instance of
another type of server control and add that to theControlscollection in theCreateChildControls
method When you run this sample, you see that it renders a text box just like the last control did In fact, the HTML that it renders is almost identical
Exposing Child Control Properties
When you drop a composite control (such as the text box from the last sample) onto the design
sur-face, notice that even though you are using a powerful ASP.NET TextBox control within the control,
none of that control’s properties are exposed to you in the Properties Explorer In order to expose
child control properties through the parent container, you must create corresponding properties in the
parent control For example, if you want to expose the ASP.NET text boxTextproperty through
the parent control, you create aTextproperty Listing 26-34 shows how to do this
Listing 26-34: Exposing control properties in a composite control
VB
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text")> _
<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _
Public Class ServerControl1
Inherits System.Web.UI.WebControls.CompositeControl
Protected textbox As TextBox
Public Property Text() As String
1245
Trang 6Get EnsureChildControls() Return textbox.Text End Get
Set(ByVal value As String) EnsureChildControls() textbox.Text = value End Set
End Property
Protected Overrides Sub CreateChildControls()
Me.Controls.Add(textbox) Me.ChildControlsCreated=True End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : CompositeControl
{
protected TextBox textbox = new TextBox();
public string Text {
get { EnsureChildControls();
return textbox.Text;
} set { EnsureChildControls();
textbox.Text = value;
} } protected override void CreateChildControls() {
this.Controls.Add(textbox);
this.ChildControlsCreated=true;
} }
}
1246
Trang 7Notice that you use this property simply to populate the underlying control’s properties Also notice
that before you access the underlying control’s properties, you always call theEnsureChildControls
method This method ensures that children of the container control have actually been initialized before you attempt to access them
Templated Controls
In addition to composite controls, you can also create templated controls Templated controls allow the user
to specify a portion of the HTML that is used to render the control, and to nest other controls inside of a container control You might be familiar with the Repeater or DataList control These are both templated controls that let you specify how you want the bound data to be displayed when the page renders
To demonstrate a templated control, the following code gives you a simple example of displaying a mes-sage from a user on a Web page Because the control is a templated control, the developer has complete control over how the message is displayed
To get started, create the Message server control that will be used as the template inside of a container
control Listing 26-35 shows the class which simply extends the existing Panel control by adding two
additional properties, Name and Text, and a new constructor
Listing 26-35: Creating the templated control’s inner control class
VB
Public Class Message
Inherits System.Web.UI.WebControls.Panel
Implements System.Web.UI.INamingContainer
Private _name As String
Private _text As String
Public Sub New(ByVal name As String, ByVal text As String)
_text = text _name = name End Sub
Public ReadOnly Property Name() As String
Get Return _name End Get
End Property
Public ReadOnly Property Text() As String
Get Return _text End Get
End Property
End Class
C#
using System;
using System.Text;
using System.Web;
1247
Trang 8using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
public class Message : Panel, INamingContainer
{
private string _name;
private string _text;
public Message(string name, string text) {
_text = text;
_name = name;
} public string Name {
get { return _name;}
} public string Text {
get { return _text;}
} }
}
As you will see in a moment, you can access the public properties exposed by theMessageclass in
order to insert dynamic content into the template You will also see how you can display the values
of theNameandTextproperties as part of the rendered template control
Next, as shown in Listing 26-36, create a new server control which will be the container for the
Messagecontrol This server control is responsible for rendering any template controls nested in it
Listing 26-36: Creating the template control container class
VB
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text")> _
<ToolboxData("<{0}:TemplatedControl runat=server></{0}:TemplatedControl>")> _
Public Class TemplatedControl
Inherits System.Web.UI.WebControls.WebControl
Private _name As String
Private _text As String
1248
Trang 9Private _message As Message
Private _messageTemplate As ITemplate
<Browsable(False)> Public ReadOnly Property Message() As Message
Get
Return _message
End Get
End Property
<PersistenceMode(PersistenceMode.InnerProperty), _
TemplateContainer(GetType(Message))> _
Public Property MessageTemplate() As ITemplate
Get
Return _messageTemplate
End Get
Set(ByVal value As ITemplate)
_messageTemplate = value
End Set
End Property
<Bindable(True), DefaultValue("")> Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
<Bindable(True), DefaultValue("")> Public Property Text() As String
Get
Return _text
End Get
Set(ByVal value As String)
_text = value
End Set
End Property
Public Overrides Sub DataBind()
CreateChildControls()
ChildControlsCreated = True
MyBase.DataBind()
End Sub
Protected Overrides Sub CreateChildControls()
Me.Controls.Clear()
_message = New Message(Name, Text)
If Me.MessageTemplate Is Nothing Then
Me.MessageTemplate = New DefaultMessageTemplate()
End If
1249
Trang 10Me.MessageTemplate.InstantiateIn(_message) Controls.Add(_message)
End Sub
Protected Overrides Sub RenderContents( _
ByVal writer As System.Web.UI.HtmlTextWriter) EnsureChildControls()
ChildControlsCreated = True MyBase.RenderContents(writer) End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:TemplatedControl runat=server></{0}: TemplatedControl >")]
public class TemplatedControl : WebControl
{
private string _name;
private string _text;
private Message _message;
private ITemplate _messageTemplate;
[Browsable(false)]
public Message Message {
get { return _message;
} } [PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(Message))]
public virtual ITemplate MessageTemplate {
get { return _messageTemplate;}
set { _messageTemplate = value;}
}
1250