Hit Enter and Post Back Revisited

Build a Custom Postback Control in ASP.NET 2.0

CoreCoder

LANGUAGES: VB.NET

ASP.NET VERSIONS: 2.0

 

Hit Enter and Post Back Revisited

Build a Custom Postback Control in ASP.NET 2.0

 

By Dino Esposito

 

In the February 2004 issue of asp.netPRO, I wrote an article to demonstrate an enhanced version of the TextBox control that captures the Enter key and posts back (see Hit Enter and Post Back). Most of the time, ASP.NET pages post back through user clicks either submit buttons or link buttons. In other cases, if the auto-postback feature is turned on, some list controls (e.g., ListBox and DropDownList) may post back as the user changes the current selection. In general, the postback event can be triggered by any event that can be detected on the client, including drag-and-drop, mouse movements, keyboard activity, and timeouts. You can build custom controls around any of these HTML events and manage to expose related server-side events.

 

In this article, I ll revisit the source code of the PostTextBox control to obtain a new control that provides the same set of features but is specifically designed for ASP.NET 2.0. For a postback control, being specifically designed for ASP.NET 2.0 primarily means one thing: supporting cross-page postbacks.

 

Posting with the TextBox Control

First off, it is interesting to recall that if you create a sample page that contains exactly one TextBox control (plus any other combination of server controls), give focus to the TextBox, then hit Enter, the page posts back automatically and without any efforts of your own. If you add a second TextBox control (or even a client input text field) to the page, the magic effect ends and the page won t post back until you click a submit button.

 

End users, especially those who grew up with non-Windows computers and who may not yet be accustomed to using the mouse, may find hitting the Enter key a much more natural and faster way to close the form and submit some data. In Web pages, however, the idea of posting data to a server is naturally associated with the idea of clicking a button. In ASP.NET 2.0, this relationship has been formalized by defining a new interface IButtonControl. The interface defines the members that ASP.NET expects to find in server controls that post back. To be precise, not all ASP.NET 2.0 controls that have the ability to post back actually implement the interface. The only exception, though, are list controls that post back only when their AutoPostBack property is set to true. Let s learn more about the IButtonControl interface and how to implement it in a custom TextBox control.

 

The IButtonControl Interface

One of the goals of the IButtonControl interface is refactoring a portion of the existing control functionality into more homogeneous subsets of members. The IButtonControl interface defines the properties and events that characterize a control that acts like a button on a Web page. Similarly, the interfaces ITextControl and IEditableTextControl group properties and events common to all controls that display, and optionally edit, a text. Implementing any of these interfaces doesn t make the control necessarily richer in terms of functions, but certainly more readable and easier to extend and customize. The following code snippet shows the declaration of the IButtonControl interface:

 

Public Interface IButtonControl

     ' Events

     Event Click As EventHandler

     Event Command As CommandEventHandler

     ' Properties

     Property CausesValidation As Boolean

     Property CommandArgument As String

     Property CommandName As String

     Property PostBackUrl As String

     Property [Text] As String

     Property ValidationGroup As String

End Interface

 

The table in Figure 1 details the various members. As you can see, the interface lists properties that relate to the action of posting back. The events, though, are those typical of button controls and don t perfectly map (at least as far as names are concerned) to a TextBox control even a TextBox that behaves and posts back like a button.

 

Property

Description

CausesValidation

Indicates whether validation is performed when the control posts back.

CommandArgument

Gets or sets an optional parameter passed to the control s Command event along with the associated CommandName.

CommandName

Gets or sets the command name associated with the control.

PostBackUrl

Indicates the URL that will handle the postback triggered through the button control.

Text

Gets or sets the text displayed by the control.

ValidationGroup

Gets or sets the name of the validation group to which the control belongs.

Visible

Indicates whether the control will be rendered or kept hidden.

 

Event

Description

Click

Event raised when the control posts back. The event passes no information to the page.

Command

Event raised when the control posts back; more specific than, and subsequent to, Click. The event passes command name and argument to the page event handler.

Figure 1: The IButtonControl interface.

 

The PostTextBox Control

The PostTextBox control is a regular TextBox control except that it posts back if the user hits Enter when the control holds the input focus. Ideally, one would design such a control as shown in the following code snippet:

 

Public Class PostTextBox

      Inherits WebControl

      Implements IButtonControl,

                 IPostBackDataHandler,

                 IEditableTextControl,

                 ITextControl

 

This is exactly the signature of the TextBox class plus the IButtonControl interface. If you opt for this approach, though, be prepared to rewrite much of the code that the ASP.NET team has hardcoded in the implementation of the native TextBox control. In addition, a conflict would arise between the members of the ITextControl and IButtonControl interface. Both, therefore, have a method named Text of type string. The conflict can be easily removed by dropping the ITextControl interface. The interface, in fact, features only the Text member, which is already part of the control if the IButtonControl interface is supported.

 

A better solution might be inheriting the PostTextBox from TextBox:

 

Public Class PostTextBox

      Inherits TextBox

      Implements IButtonControl

 

The interfaces IPostBackDataHandler, IEditableTextControl, and ITextControl are not explicitly listed because they are implemented by the base class. The conflict on the Text property is not eliminated; in addition, other conflicts arise on the other two properties in the IButtonControl interface: ValidationGroup and CausesValidation. Both properties are exposed by the TextBox class.

 

You can remove any conflicts by using the Shadows keyword (new in C#) to shadow the inherited member and redefine it as a member of the implemented interface. In terms of implementation, you can always refer to the base member using the MyBase keyword in Visual Basic .NET (and base in C#). Listing One shows the implementation of the IButtonControl in the PostTextBox control.

 

The PostTextBox control outputs an INPUT field whose onkeypress event is bound to a piece of JavaScript code. The JavaScript code captures any keystroke; if the key code equals 13 (the Enter key), a regular postback is made. Figure 2 shows the server code that adds proper client script to the PostTextBox control.

 

Private Sub AddBehavior()

 RegisterEnterKeyHandler()

 Attributes("onkeypress") = "CaptureEnter(this)"

End Sub

Private Sub RegisterEnterKeyHandler()

 ' Build the Javascript code to capture the Enter key

 Dim builder As New StringBuilder

 builder.AppendLine("function CaptureEnter(ctl) {")

 builder.AppendLine("   var key = window.event.keyCode;")

 builder.AppendLine("   if (key == 13) {")

 builder.AppendLine("      __doPostBack(ctl.name, '');")

 builder.AppendLine("      return;")

 builder.AppendLine("   }")

 builder.AppendLine("}")

 ' Register the script

 Dim js As String = builder.ToString()

 If Not Page.ClientScript.IsClientScriptBlockRegistered( _

         "CaptureEnter") Then

    Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _

         "CaptureEnter", js, True)

 End If

 ' Ensure that __doPostBack is declared in the page

 Page.ClientScript.GetPostBackEventReference(Me, "")

End Sub

Figure 2: Adding client script to the PostTextBox control.

 

The AddBehavior method is invoked from within the OnLoad override while the control is being loaded in the request processing:

 

Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)

   MyBase.OnLoad(e)

   AddBehavior()

End Sub

 

At this point, you can place any number of PostTestBox controls in a page, move the input focus to any of them, hit Enter, and, voil , the page posts back. This is not enough, though, to fire a server event that the page author can handle to implement some logic. To add a postback event handler, a control implements yet another interface, IPostBackEventHandler:

 

Public Interface IPostBackEventHandler

  Sub RaisePostBackEvent(ByVal eventArgument As String)

End Interface

 

Figure 3 shows the typical ASP.NET 2.0 implementation of the interface. First you set the control to validate that the event originated from the user interface that was originally rendered by the same control. In this way, the control will not respond to any spoofed event notification. The ValidateEvent on the page s ClientScript object does the trick. Next, if validation is enabled, you call the Validate method on the page specifying the validation group to which the PostTextBox control belongs. Finally, you fire the two server events in the IButtonControl interface: Click and Command.

 

Public Sub RaisePostBackEvent(ByVal eventArgument As String) _

      Implements IPostBackEventHandler.RaisePostBackEvent

   Page.ClientScript.ValidateEvent(UniqueID, eventArgument)

   If CausesValidation Then

        Page.Validate(ValidationGroup)

   End If

   OnClick(EventArgs.Empty)

   OnCommand(New CommandEventArgs(CommandName, CommandArgument))

End Sub

Figure 3: Implementation of the IPostBackEventHandler interface.

 

Note that you re not forced to implement IButtonControl; if you don t implement the interface but still bring in nearly the same members, you can rename the Click event to a more intuitive EnterPressed or Posted, or whatever else you like.

 

Figure 4 shows a sample page with two PostTextBox controls. The second textbox is bound to a regular expression validator; when you hit Enter, the validation occurs and prevents the page from posting back in case of errors.

 


Figure 4: Sample page in action.

 

Cross-page PostBack

As mentioned, the PostTextBox control implements the IButtonControl interface, which includes the PostBackUrl property. The property is used to perform cross-page postbacks and indicates the URL to post to from the current page when the Enter key is pressed. When PostBackUrl is used, the JavaScript code to trigger the postback changes. To obtain the cross-page postback JavaScript code, you call a different overload of the same GetPostBackEventReference method you use for regular postbacks:

 

Dim options As New PostBackOptions(Me)

options.ActionUrl = PostBackUrl

postbackStatement = Page.ClientScript. _

 GetPostBackEventReference(options)

 

The generated script changes to the following:

 

WebForm_DoPostBackWithOptions(

 new WebForm_PostBackOptions(ctl.name, "", false, "", _

   "target.aspx", false, true));

 

As a result, when the user presses the Enter key on a PostTextBox control, the page posts back and the user is redirected to the specified page (target.aspx in the preceding example).

 

Conclusion

The TextBox control is not designed to handle the Enter key. Nonetheless, many users at the end of a form find it natural to press Enter instead of moving the mouse and clicking a submit button. In a page with a single textbox, pressing Enter when the textbox holds the input focus works just fine and the page posts back. However, it doesn t work for pages with more than one TextBox. That s why you need to have a specialized TextBox control to handle the Enter keystroke properly. In this article, I ve discussed a custom PostTextBox control that implements the IButtonControl interface (a new interface in ASP.NET 2.0) and supports validation and cross-page postbacks.

 

The sample code accompanying this article is available for download.

 

Dino Esposito is a Solid Quality Learning mentor and the author of Programming Microsoft ASP.NET 2.0 Core Reference and Programming Microsoft ASP.NET 2.0 Applications-Advanced Topics, both from Microsoft Press. Based in Italy, Dino is a frequent speaker at industry events worldwide. Join the blog at http://weblogs.asp.net/despos.

 

Begin Listing One Implementation of the IButtonControl interface

Public Event Click(ByVal sender As Object, ByVal e As _

      EventArgs) Implements IButtonControl.Click

Public Event Command(ByVal sender As Object, ByVal e As _

      CommandEventArgs) Implements IButtonControl.Command

Public Shadows Property CausesValidation() As Boolean _

      Implements IButtonControl.CausesValidation

      Get

          Return MyBase.CausesValidation

      End Get

      Set(ByVal value As Boolean)

          MyBase.CausesValidation = value

      End Set

End Property

Public Property CommandArgument() As String _

     Implements IButtonControl.CommandArgument

     Get

         Dim o As Object = ViewState("CommandArgument")

         If o Is Nothing Then

            Return String.Empty

         End If

         Return DirectCast(o, String)

     End Get

     Set(ByVal value As String)

         ViewState("CommandArgument") = value

     End Set

End Property

Public Property CommandName() As String _

      Implements IButtonControl.CommandName

     Get

         Dim o As Object = ViewState("CommandName")

         If o Is Nothing Then

            Return String.Empty

         End If

         Return DirectCast(o, String)

     End Get

     Set(ByVal value As String)

         ViewState("CommandName") = value

     End Set

End Property

Public Property PostBackUrl() As String _

      Implements IButtonControl.PostBackUrl

      Get

          Dim o As Object = ViewState("PostBackUrl")

          If o Is Nothing Then

             Return String.Empty

          End If

          Return DirectCast(o, String)

      End Get

      Set(ByVal value As String)

          ViewState("PostBackUrl") = value

      End Set

End Property

Public Shadows Property Text() As String _

      Implements IButtonControl.Text

      Get

          Return MyBase.Text

      End Get

      Set(ByVal value As String)

          MyBase.Text = value

      End Set

End Property

Public Shadows Property ValidationGroup() As String _

      Implements IButtonControl.ValidationGroup

      Get

         Return MyBase.ValidationGroup

      End Get

      Set(ByVal value As String)

          MyBase.ValidationGroup = value

      End Set

End Property

End Listing One

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish