The sample downloadable solution (zip) is entirely developed using Visual Studio.NET 2003 Enterprise Architect on Windows Server 2003 Standard Edition. But, I am confident that it would work with other versions of Windows (which support .NET 1.1) as well.
Introduction
Everyone knows that ASP.NET already contains a flexible TextBox control to design web applications with ease. You can even develop your own custom control using the existing TextBox control by deriving it from the “TextBox” class (available in the ASP.NET framework). Of course, everyone knows this too. But not everyone knows that we can design a TextBox completely from scratch with our own control over the complete implementation.
In my previous article (Developing ASP.NET Custom Server Controls: Introduction), I already introduced how to design and implement our own custom server control from the scratch. If you are quite new to the concept of custom controls in ASP.NET, I suggest you go through the article specified above. But it doesn’t support “postback” or “viewstate” features.
Even though I could use System.Web.UI.Control as the base class for my textbox control, I selected System.Web.UI.WebControls.WebControl as the base class, because of the convenience and ease. Apart from all of these, we will also implement support for “postback” and “viewstate.” We will also examine client-side JavaScript, being emitted from our control, which is what makes it cute looking!
The System.Web.UI.Control class has only a few rendering methods which could be overridden. This gives us less flexibility in developing the custom control, when we compare it with the rendering methods available in the System.Web.UI.WebControls.WebControl class. Of course, some of the most important properties (like width, height, font, and so on) of the WebControl class get inherited to our textbox control.
Before talking too much about the control, let us go to the implementation first. We will create a Visual Studio.NET 2003 solution throughout this article with more than one project.
Now, we will develop a simple “Textbox” type of control right from scratch. I call it “MyTextBox” throughout this article. The following steps help you to create the custom control using Visual Studio.NET 2003.
Click start -> Programs -> Microsoft Visual Studio .NET 2003 ->Microsoft Visual Studio .NET 2003 to open the IDE (Integrated Development Environment).
Click File -> New -> Project.
Within the “new project” dialog box select “visual basic projects” as the project type, “Web Control Library” as the template and provide the name “SimpleCustomControl” along with the location you desire (Figure:1), and finally click “ok.”
Within the solution explorer, right-click on “WebCustomControl1.Vb” and select “delete” to delete it.
Go to the project menu and select “Add New Item.”
Within the “Add New Item” dialog box select “WebCustomControl” and name it “MyTextBox.vb.”
Modify code (or just copy and paste) in the editor as follows:
Imports System.ComponentModel
Imports System.Web.UI
<DefaultProperty("Text"), ToolboxData("<{0}:MyTextBox runat=server></{0}:MyTextBox>")> Public Class MyTextBox
Inherits System.Web.UI.WebControls.WebControl
Implements IPostBackDataHandler
Property [Text]() As String
Get
Return viewstate("text") & ""
End Get
Set(ByVal Value As String)
viewstate("text") = Value
End Set
End Property
Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized. NameValueCollection) As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
If Text <> postCollection(Me.UniqueID) Then
Text = postCollection(Me.UniqueID)
Return True
End If
Return False
End Function
Public Sub RaisePostDataChangedEvent() Implements System.Web.UI.IPostBackDataHandler. RaisePostDataChangedEvent
The previous section just created the custom control. We need to test the custom control using a web application. Now, we shall create a web application (within the same solution as above), refer to the previous web control, drag it onto the web page and finally test it. The following steps would guide you through the process.
Within the same solution, Go to File -> Add Project -> New Project
Select the project type as “ASP.NET Web Application,” replace the location with “http://localhost/webapplication1” and click “ok.” Within the solution explorer, right-click on the solution, go to the properties, select the “Single Startup Project” radio button and select “SimpleCustomControlTest” in the dropdown list, which is right below that radio button and finally click “ok.”
Within the solution explorer open the “SimpleCustomControlTest” project and select “References.” Right-click on “references” and select “Add Reference.”
Within the “Add Reference” dialog box, select “Projects” tab and click on “select” button and click “ok” as shown in the following figure (2).
Open the tool box, right-click on “Web Forms” and select “Add/Remove Items.”
In the “Custom Toolbox” dialog box, click “browse” and go to the bin folder of the “SimpleCustomControl” project. Select the “SimpleCustomControl.dll” file, click “Open” and click “Ok.”
You should be able to see a new control within the “web forms” section of the tool box named “MyTextBox” (it generally gets added at the bottom).
Drag as many “MyTextBox”es as you want onto the “WebForm1.aspx” in design mode.
Drag two buttons and change the text as “Show” and “PostBack” respectively.
Modify the “button1_click” event (of “Show” button) as follows:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.MyTextBox1.Text = "hello world"
End Sub
Execute the solution, type some messages in all of the textboxes and try to “postback.” You can even click the “Show” button.
In this section, we shall go into the details of the “MyTextBox” custom control. First of all let us consider the following line:
Public Class MyTextBox
Inherits System.Web.UI.WebControls.WebControl
Implements IPostBackDataHandler
I already explained that any custom control (or class of custom control) needs to be derived either from System.Web.UI.Control or System.Web.UI.WebControls.WebControl. The above statement does exactly this. Until there we are all right. But what is the use of “IPostBackDataHandler”? This is the interface we need to implement to support the feature of “postback.” We shall see its details later. Let us proceed to the following code fragment:
Property [Text]() As String
Get
Return viewstate("text") & ""
End Get
Set(ByVal Value As String)
viewstate("text") = Value
End Set
End Property
I hope you can understand the above. I define a property named “text,” which has the “viewstate” support. Any information we store in “viewstate” would exist to the server even after further web requests from the same page in a magical manner.
All of the information available in “viewstate” will be encoded and added to a hidden field to the same page by the ASP.NET runtime. When a post back occurs, all the information in that hidden field again gets posted to the server along with new pairs of values. We then check (or compare) the previous values (or information in viewstate) with recently modified values by the user and modify the view state accordingly during a “postback” event. This could be observed better from the next section.
Continuing with the above code, we have:
Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
The above code fragment is at the heart of displaying the “textbox.” First of all, I add all the attributes of the “input” tag such as name, id, type, value, and so forth using the “output.AddAttribute” method. “UniqueID” and “ClientID” are automatically generated when a control has been dragged from the toolbox on to the web form.
“MyBase.AddAttributesToRender(output)” is the statement which is essential to making it available as the first statement. All of the default attributes, such as “style” (what we set at design time using the properties window) will be added using that simple statement. If you forget that statement, you will be left with a very plain textbox without having any of your design time properties set.
In the previous section, I already explained the “viewstate” and how to handle it in a very easy manner using a simple “text” property. This section explains the implementation of “postback” in our control.
As you know, in general, any server control in ASP.NET maintains its “state” even after a “postback.” The “postback” could occur in several ways, including by just clicking a “submit” button. Within our control, I would like to maintain the same. As I am already maintaining the “state” information through “viewsate,” I need to refresh (or place) the latest value (or information) within my control before the page gets disposed. This could be solved by implementing the interface “IPostBackDataHandler.” Let us consider the following code:
Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized. NameValueCollection) As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
If Text <> postCollection(Me.UniqueID) Then
Text = postCollection(Me.UniqueID)
Return True
End If
Return False
End Function
Public Sub RaisePostDataChangedEvent() Implements System.Web.UI.IPostBackDataHandler. RaisePostDataChangedEvent
End Sub
You can observe that we need to implement two methods, namely “LoadPostData” and “RaisePostDataChangedEvent.” Within the “LoadPostData,” I am comparing the value available in “viewstate” (“text” property) with the posted value (could be the same or modified value) to the server with an IF condition. If a user modifies the value, the posted value would be different and we will update the latest value back to the “viewstate” using the same “text” property.
What are “Return True” and “Return False”? When the posted values are different from our previous state values and, if we want raise any events (such as the “textchanged” event or others), we would return TRUE. This in turn executes the method “RaisePostDataChangedEvent” (currently I implemented nothing inside that, as there exist no events within my control). Returning “false” would not execute “RaisePostDataChangedEvent” at all. Actually in this scenario, I don’t need to return “true” at all, but it is just for your understanding.
No, it is not at all cute until now. How do we implement cuteness? Just imagine, I would like to have the background color of “MyTextBox” to be automatically changed to a color when it receives the user's focus (or cursor) and back to the color white after losing the focus. Is this not cute? Now we shall see how to implement this. Modify your “render” method, which looks like this:
Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
Within the Render method (above), we are just adding two more attributes to enable our control’s cuteness.
This control has been developed just to initiate you and show the power of custom controls to control everything right from beginning until the end, including client-side JavaDcript emission. I didn’t quite implement all of the features of the original ASP.NET Textbox control (as it would take a series of articles). You just need to learn a few more interfaces and methods to implement all the original features, along with your own features.
I leave it to the developers for further enhancing the same control. The areas for improving the same control would include eventing, better JavaScript for validation, data-binding, implementing styles, and so forth. Good luck.
Any comments, suggestions, bugs, errors, feedback etc. are highly appreciated at jag_chat@yahoo.com.