Suppose that you want to display all the text boxes at your Web site with a blue background and a yellow font. It might make sense, in this situation, to simply create a custom control that renders a text box with the proper attributes. For example, the control in Listing 28.20 renders an <input> tag with a blue background and yellow foreground. Listing 28.20 BlueTextBox.vbImports System Imports System.Web Imports System.Web.UI Namespace myControls Public Class BlueTextBox Inherits Control Protected Overrides Sub Render( objTextWriter As HtmlTextWriter) objTextWriter.AddAttribute( "Name", Me.UniqueID ) objTextWriter.AddStyleAttribute( "background-color", "Blue" ) objTextWriter.AddStyleAttribute( "color", "Yellow" ) objTextWriter.RenderBeginTag( "input" ) objTextWriter.RenderEndTag End Sub End Class End Namespace The C# version of this code can be found on the CD-ROM. You can display the BlueTextBox control by using the page in Listing 28.21. Listing 28.21 DisplayBlueTextBox.aspx<%@ Register TagPrefix="myControls" Namespace="myControls" Assembly="BlueTextBox"%> <html> <head><title>DisplayBlueTextBox.aspx</title></head> <body> <form Runat="Server"> <myControls:BlueTextBox Runat="Server"/> <asp:Button Text="Submit!" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. If you post the form containing the BlueTextBox control in Listing 28.21, you run into a problem. The BlueTextBox control does not retain its value between form posts. In other words, the control does not support postbacks. To get the BlueTextBox control to support postbacks, you need to do slightly more work. You need to implement the IPostBackDataHandler interface. This interface defines the following two methods :
The modified BlueTextBox control in Listing 28.22, named BlueTextBoxPostBack , illustrates how you can implement the IPostBackDataHandler interface. Listing 28.22 BlueTextBoxPostBack.vb [View full width] Imports System Imports System.Web Imports System.Web.UI Imports System.Collections.Specialized Namespace myControls Public Class BlueTextBoxPostBack Inherits Control Implements IPostBackDataHandler Public Text As String Public Function LoadPostData( PostDataKey As String, Values As NameValueCollection) As Boolean _ Implements IPostBackDataHandler.LoadPostData Text = Values( Me.UniqueID ) Return False End Function Public Sub RaisePostDataChangedEvent() _ Implements IPostBackDataHandler.RaisePostDataChangedEvent ' Raise Change Event End Sub Protected Overrides Sub Render( objTextWriter As HtmlTextWriter ) objTextWriter.AddAttribute( "Name", Me.UniqueID ) objTextWriter.AddStyleAttribute( "background-color", "Blue" ) objTextWriter.AddStyleAttribute( "color", "Yellow" ) objTextWriter.AddAttribute( "value", Text ) objTextWriter.RenderBeginTag( "input" ) objTextWriter.RenderEndTag End Sub End Class End Namespace The C# version of this code can be found on the CD-ROM. You add one new function and one new subroutine in Listing 28.22. The LoadPostData function has two parameters. The first parameter, PostDataKey , represents the unique ID for the control. The second parameter, Values , represents the values of all the form elements being posted back to the server. NOTE In Listing 28.22, the first parameter passed to the LoadPostData function is an instance of the NameValueCollection collection. At the top of Listing 28.22, you import System.Collections.Specialized so that you have access to this collection. Within the LoadPostData function, you grab the value from the Values collection for the current control and assign it to the string variable named Text . Next, you return the value False from the function. The RaisePostBackDataChanged subroutine is called only when the LoadPostData function returns the value True . In Listing 28.22, you don't do anything with this subroutine. I'll explain its purpose in a moment. Within the Render method, you add an additional attribute, named Value , to the text box by using the AddAttribute method. You assign the value of the Text property to this attribute. The page in Listing 28.23 illustrates how you can display the new and improved BlueTextBox control. Listing 28.23 DisplayBlueTextBoxPostBack.aspx<%@ Register TagPrefix="myControls" Namespace="myControls" Assembly="BlueTextBoxPostBack"%> <html> <head><title>DisplayBlueTextBoxPostBack.aspx</title></head> <body> <form Runat="Server"> <myControls:BlueTextBoxPostBack Runat="Server"/> <asp:Button Text="Submit!" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. If you enter data in the text box in Listing 28.23 and submit the form, the text box redisplays the data when the form is reloaded. Remember that the BlueTextBox control had an additional subroutine, named RaisePostDataChangedEvent , which you ignored earlier. You can use this subroutine to raise a change event whenever the data in the text box changes. The control in Listing 28.24 illustrates how to do so. Listing 28.24 BlueTextBoxChanged.vb [View full width] Imports System Imports System.Web Imports System.Web.UI Imports System.Collections.Specialized Namespace myControls Public Class BlueTextBoxChanged Inherits Control Implements IPostBackDataHandler Public Event TextChanged( s As Object, e As EventArgs ) Public Property Text As String Set ViewState( "Text" ) = Value End Set Get If ViewState( "Text" ) <> Nothing Then Return ViewState( "Text" ) Else Return String.Empty End If End Get End Property Public Function LoadPostData( PostDataKey As String, Values As NameValueCollection ) As Boolean _ Implements IPostBackDataHandler.LoadPostData Dim strNewValue As String strNewValue = Values( Me.UniqueID ) If strNewValue <> Text Then Text = strNewValue Return True Else Return False End If End Function Public Sub RaisePostDataChangedEvent() _ Implements IPostBackDataHandler.RaisePostDataChangedEvent OnTextChanged( EventArgs.Empty ) End Sub Protected Sub OnTextChanged( e As EventArgs ) RaiseEvent TextChanged( Me, e ) End Sub Protected Overrides Sub Render( objTextWriter As HtmlTextWriter ) objTextWriter.AddAttribute( "Name", Me.UniqueID ) objTextWriter.AddStyleAttribute( "background-color", "Blue" ) objTextWriter.AddStyleAttribute( "color", "Yellow" ) objTextWriter.AddAttribute( "value", Text ) objTextWriter.RenderBeginTag( "input" ) objTextWriter.RenderEndTag End Sub End Class End Namespace The C# version of this code can be found on the CD-ROM. In Listing 28.24, you modify both the LoadPostData function and RaisePostDataChangedEvent subroutine. The LoadPostData function will now return True when the contents of the text box are changed. The new value entered into the text box is compared against a value saved in the control's view state. If the LoadPostData function returns True , the RaisePostDataChangedEvent subroutine executes. This subroutine calls the OnTextChanged subroutine, which, in turn , raises the TextChanged event. The ASP.NET page in Listing 28.25 illustrates how you can handle the OnTextChanged event. Listing 28.25 DisplayBlueTextBoxChanged.aspx<%@ Register TagPrefix="myControls" Namespace="myControls" Assembly="BlueTextBoxChanged"%> <Script Runat="Server"> Sub BlueTextBoxChanged_TextChanged( s As Object, e As EventArgs ) lblMessage.Text = "Text Changed!" End Sub </Script> <html> <head><title>DisplayBlueTextBoxChanged.aspx</title></head> <body> <form Runat="Server"> <myControls:BlueTextBoxChanged OnTextChanged="BlueTextBoxChanged_TextChanged" Runat="Server"/> <asp:Button Text="Submit!" Runat="Server" /> <p> <asp:Label ID="lblMessage" ForeColor="Red" Font-Bold="True" EnableViewState="False" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. When the BlueTextBoxChanged control is declared in Listing 28.25, the BlueTextBoxChanged_TextChanged subroutine is associated with the TextChanged event. If you submit the form containing the control and the contents of the control have been modified, the TextChanged event triggers the BlueTextBoxChanged_TextChanged subroutine. Handling Postback EventsOne last topic not yet examined concerns postbacks. In the preceding section, you learned how to repopulate a text box after a form is submitted. However, I have not discussed a method for actually posting the data from a form. You can use three standard ASP.NET controls to post a form: Button , ImageButton , and LinkButton . All three controls generate client-side JavaScript that is executed when you submit a form. In this section, you learn how to create your own form element that generates the necessary JavaScript to raise a postback event. To handle postback events from a custom control, you must implement the IPostBackEvent interface. This interface contains a definition for a single method: the RaisePostBack event. The control in Listing 28.26 illustrates how you can implement this method in a custom control. Listing 28.26 TextBoxColor.vb [View full width] Imports System Imports System.Web Imports System.Web.UI Imports System.Collections.Specialized Namespace myControls Public Class TextBoxColor Inherits Control Implements IPostBackDataHandler Implements IPostBackEventHandler Public BoxColor As String = "Blue" Public Text As String Public Sub RaisePostBackEvent(EventArgument As String) _ Implements IPostBackEventHandler.RaisePostBackEvent If (eventArgument = "Red" ) Me.BoxColor = "Red" Else Me.BoxColor = "Blue" End If End Sub Public Function LoadPostData(PostDataKey As String, Values As NameValueCollection) As Boolean _ Implements IPostBackDataHandler.LoadPostData Dim strNewValue As String Text = Values( Me.UniqueID ) Return False End Function Public Sub RaisePostDataChangedEvent() _ Implements IPostBackDataHandler.RaisePostDataChangedEvent ' Raise Change Event End Sub Protected Overrides Sub Render( objTextWriter As HtmlTextWriter ) objTextWriter.AddAttribute( "Name", Me.UniqueID ) objTextWriter.AddStyleAttribute( "background-color", BoxColor ) objTextWriter.AddStyleAttribute( "color", "Yellow" ) objTextWriter.AddAttribute( "value", Text ) objTextWriter.RenderBeginTag( "input" ) objTextWriter.RenderEndTag objTextWriter.WriteLine( "<p>" ) objTextWriter.AddAttribute( "Type", "Button" ) objTextWriter.AddAttribute( "Value", "Display Red!" ) objTextWriter.AddAttribute( "OnClick", "JScript:" & Page.GetPostBackEventReference( Me, "Red" ) ) objTextWriter.RenderBeginTag( "Input" ) objTextWriter.RenderEndTag() objTextWriter.WriteLine( " " ) objTextWriter.AddAttribute( "Type", "Button" ) objTextWriter.AddAttribute( "Value", "Display Blue!" ) objTextWriter.AddAttribute( "OnClick", "JScript:" & Page.GetPostBackEventReference( Me, "Blue" ) ) objTextWriter.RenderBeginTag( "Input" ) objTextWriter.RenderEndTag() End Sub End Class End Namespace The C# version of this code can be found on the CD-ROM. The control in Listing 28.26 displays a text box and two buttons . When you click the button labeled Display Red! , the background color of the text box changes to red. When you click the button labeled Display Blue! , the background color changes to blue. Both buttons are rendered within the control's Render method. They are created with an OnClick attribute that has a JScript function as its value. For example, the OnClick attribute for the Display Red! button is declared like this: [View full width]
The GetPostBackEventReference method returns a reference to the JavaScript function on the client; this reference causes the form to be posted back to the server. The first parameter passed to the method represents the control that will process the postback event on the server. In this case, you use the Visual Basic keyword Me , which refers to the current control. The second parameter is optional. It's an argument passed back to the server during postback. In this case, you pass back the argument "Red" so that you can detect that the Display Red! button was clicked. When the Display Red! button is rendered, the following code is sent to the browser: <input Type="Button" Value="Display Red!" OnClick="JScript:__doPostBack ('ctrl4','Red') " /> The Display Red! button triggers the client-side JavaScript function named __doPostBack . Notice that the unique ID of the control and parameter are passed by the function. You can view the source of the __doPostBack function by selecting View Source on your browser. In case you're curious , the __doPostBack function looks like this: function __doPostBack(eventTarget, eventArgument) { var theform = document.ctrl1 theform.__EVENTTARGET.value = eventTarget theform.__EVENTARGUMENT.value = eventArgument theform.submit() } The __doPostBack function initializes two arguments and submits the form back to the server. When the form is posted back to the server, the custom control's RaisePostBack method is executed. This method looks like this: Public Sub RaisePostBackEvent(EventArgument As String) _ Implements IPostBackEventHandler.RaisePostBackEvent If (eventArgument = "Red" ) Me.BoxColor = "Red" Else Me.BoxColor = "Blue" End If End Sub This method detects whether Display Red! or Display Blue! was clicked. If the Display Red! button was clicked, the BoxColor property is assigned the value Red . Otherwise, the property is assigned the value Blue . When the control renders the text box in the control's Render method, it uses the value of the BoxColor property when setting the background color of the text box. You can test the TextBoxColor control by using the ASP.NET page in Listing 28.27. Listing 28.27 DisplayTextBoxColor.aspx<%@ Register TagPrefix="myControls" Namespace="myControls" Assembly="TextBoxColor"%> <html> <head><title>DisplayTextBoxColor.aspx</title></head> <body> <form Runat="Server"> <myControls:TextBoxColor Runat="Server"/> </form> </body> </html> The C# version of this code can be found on the CD-ROM. |