HomeASP.NET ASP.NET Custom Server Controls: Cute ASP.N...
ASP.NET Custom Server Controls: Cute ASP.NET TextBox Control Continued
In my previous article, I introduced you to how to create your own TextBox control with cool features without even deriving it from an existing ASP.NET TextBox control. In this article we will further enhance the same control with new rendering features, together with client-side JavaScript emission in a most flexible manner.
A file for this article is available for download here.
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
My previous articles have already shown you how to create any custom control from the scratch. Now, I will not be going into the details of creating a solution, project, etc. I will just take this opportunity to explain the features available and how they have been implemented in the above downloadable VS.NET solution.
In this article, I used four new methods of rendering (as opposed to only one “render” method in my previous articles). They are as follows:
RenderBeginTag
RenderContents
RenderEndTag
AddAttributesToRender
To be frank, all of the above methods are not really necessary for the TextBox control I developed. But, this gives me an opportunity to explain all four simultaneously. We can also implement all of our controls in a single “render” method as well. But, the above methods give much more flexibility by separating various divisions of rendering.
Now, if we don’t want to consider just the “render” method, we can forget about it completely and work on the other three methods, namely “RenderBeginTag,” “RenderContents,” and “RenderEndTag.” In fact, the “Render” method internally calls all these methods. “AddAttributesToRender” method is a special case, where it gets executed from within “RenderBeginTag.”
The “RenderBeginTag” should generally be implemented with all the opening tags of the control (together with their attributes). “RenderContents” generally contains the information which is required to be displayed (even child control information) within the same control. Finally, “RenderEndTag” should be implemented with all the closing tags which were opened in “RenderBeginTag.”
The default “Render” method (when not overridden by us) usually calls the “RenderBeginTag” before calling any other methods. The “RenderBeginTag” method in my control has been implemented something like this:
Public Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
AddAttributesToRender(writer)
writer.RenderBeginTag(HtmlTextWriterTag.Input)
End Sub
Within the above method, I am trying to call the “AddAttributesToRender(Writer)” statement to add any attributes to my textbox control (the INPUT tag). In fact, it is not a user defined method; it has been already defined within the “WebControl” class, and I am about to override it. Usually, the “AddAttributesToRender” method gets initiated from within the “RenderBeginTag” method (that too as the first statement). I hope you can understand the second statement, which actually renders only an INPUT tag (with all the attributes emitted by “AddAttributesToRender” method).
Coming to the next code fragment, I have an empty method as follows:
Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)
End Sub
The above method does nothing. Then is it necessary to include it? Maybe, and maybe not. If we don’t include an empty “RenderContents” method, it will try to search for child controls within our textbox control and try to render them by calling “base.Render(writer)” internally. In this case, we don’t have any child controls. So, I don’t need the default implementation (which actually calls the base class related “render” method to render all child controls). So, I override that method and make it empty.
It doesn’t matter; even if you omit the above code fragment, it would do an unnecessary search for child controls and finally leave off. Including the above fragment is a professional way to let others know about the life cycle.
Going further we have the following:
Public Overrides Sub RenderEndTag(ByVal writer As System.Web.UI.HtmlTextWriter) writer.RenderEndTag() EndSub
The above method simply contains the statement “writer.RenderEndTag”. We already opened a beginning tag using “writer.RenderBeginTag(…)” within the “RenderBeginTag” method. We didn’t close it anywhere. And we do that using the above method. You need not even specify which tag to close. It could automatically understand (from our proper HTML hierarchy) which tag to close. That’s the beauty of ASP.NET custom control development.
In the previous section, we saw the methods implemented for rendering the control. But, we didn’t deal much with the “AddAttributesToRender” method. In this section, we will discuss it.
The “AddAttributesToRender” method is basically used (or overridden) to add HTML attributes and styles that need to be rendered for the respective custom control. In my solution, it has been implemented as follows:
I removed some of the statements (explained later) from the above method for the sake of clarity. Within the above method, if you carefully observe, you will see that the first statement is “base.AddAttributesToRender(writer)”. Is this necessary? Of courseit is. It is always a good practice to have the statement “Base.AddAttributesToRender(Writer)” as the first statement within the above method. Never remove it (unless you have any reason to do so). There also exists one more secret behind it.
During the design time of VS.NET, you may be moving the control to your favorite location (or adjusting its size, or changing some of its properties, or so on). All that information (say CSS) would be remembered and written back to our control using this statement. If you forget this statement, your control works in a floating manner at the left-top of the web page (without having any design time attributes set).
You must have observed that there exist some statements starting with “writer” as follows:
The first statement (writer.AddAttribute) is generally used to emit an attribute of a tag. You can use all existing attributes from “HtmlTextWriterAttribute” or simply provide your own string in quotations. The second statement (writer.AddStyleAttribute) is generally used to add style (or inline CSS) to a tag. You can use all existing styles from “HtmlTextWriterStyle” or simply provide your own string in quotations. Finally, I am happy to say that we have “ColorTranslator” to emit .NET based color constants to HTML based color constants.
Since we now understand some of the rendering methods of this control, let us go through some of the cute features of my textbox control. I wanted my textbox control to accept only digits, or only alphabets, or any character. For that purpose, I need to validate certain of the “KeyPress” events at client-side JavaScript. Of course, I should also expose a property to the type of input it could accept. Based on all of these considerations, I declared an enumerated data type as follows:
Public Enum tInputType [Characters] [Digits] [Alphabets] End Enum
The property has been implemented as follows:
Property InputType() As tInputType Get If viewstate("InputType") Is Nothing Then viewstate("InputType") = tInputType.Characters End If Return viewstate("InputType") End Get Set(ByVal Value As tInputType) viewstate("InputType") = Value End Set End Property
I hope you can understand the above (if you are new to view state, I suggest you go through my previous articles first). Next, I would also like my textbox to be highlighted with red background, when the user passes through the control without providing any data. That means empty value, acceptable or not. Even this should be working the JavaScript. And I designed the following property to deal with that issue:
Property IsCompulsory() As Boolean Get If viewstate("IsCompulsory") Is Nothing Then viewstate("IsCompulsory") = False End If Return viewstate("IsCompulsory") End Get Set(ByVal Value As Boolean) viewstate("IsCompulsory") = Value End Set End Property
As you understand by now, my control needs to work with JavaScript (to remove unnecessary postbacks to the server), so I implemented each of those JavaScripts as separate methods which together can be registered to the page within the “AddAttributesToRender” method. The following are the four core methods which emit the respective Javascripts:
All of the above user-defined methods together with the following code-fragment made it convenient for me to achieve what I expected. Let us consider it part by part:
If Not Page.IsStartupScriptRegistered("GotFocus") Then Page.RegisterStartupScript("GotFocus", getJS4GotFocus) End If If Not Page.IsStartupScriptRegistered("LostFocus") Then Page.RegisterStartupScript("LostFocus", getJS4LostFocus) End If
The above code makes the JavaScript registration to the aspx page only once per control.
Select Case InputType Case tInputType.Digits Page.RegisterStartupScript("DigitKeyPressed", getJS4DigitKeyPress) writer.AddAttribute("onKeyPress", "return DigitKeyPressed();") End If Case tInputType.Alphabets Page.RegisterStartupScript("AlphabetKeyPressed", getJS4AlphabetKeyPress) writer.AddAttribute("onKeyPress", "return AlphabetKeyPressed();") End If Case Else Page.RegisterStartupScript("KeyPressed", getJS4KeyPress) writer.AddAttribute("onKeyPress", "return KeyPressed();") End If End Select
I excluded the ‘if’ statements for clarity. Within the above code fragment, you can understand that the respective JavaScript is being attached based on the input type.
writer.AddAttribute("onFocus", "GotFocus();") If Not IsCompulsory Then writer.AddAttribute("onBlur", "LostFocus();") Else Page.RegisterStartupScript(Me.UniqueID & "_LostFocus", getJS4ErrorLostFocus(Me.UniqueID & "_LostFocus")) writer.AddAttribute("onBlur", Me.UniqueID & "_LostFocus();") End If
The above code makes the textbox highlighted in normal (or in red) based on the property “isCompulsory”.
Remarks
This control has been developed just to initiate and show the power of custom controls to control everything right from beginning until the end, including client-side JavaScript 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 of the original features along with your own features.
I leave it to the developers to further enhance the same control. The areas for improvement of the control would include eventing, better JavaScript for validation, data-binding, and so on. Good luck.
Any comments, suggestions, bugs, errors, feedback etc. are highly appreciated at jag_chat@yahoo.com.