Extending the ASP.NET TextField User Control

This is an extension to the previous article "Developing a Wonderful ASP.NET TextField Control" for supporting numeric features (something like a Numeric Textbox). Before proceeding with this, I strongly suggest that you go through the previous article, as I am using the same core structure as the previous user control.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 20
March 21, 2007
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

A downloadable zip file is available for this application.

The entire solution (source code) for this article is available as a free download (in the form of a zip). The source code in this article has been developed using Microsoft Visual Studio 2005 Professional Edition on Microsoft Windows Server 2003 Standard Edition. I didn't really test any of the code in any other tools/IDEs/servers/editions/versions. If you have any problems, please feel free to post in the discussion area.

I will not be repeating the explanation of user controls in this article as I already introduced the same in my previous article. Along with the introduction, I also developed a sample TextField user control featuring new functions. Now, I would like to extend the same control to support a few more functions.

A textbox which needs to have only numeric input is often required in ASP.NET applications. Numeric input is not only limited to digits. It may also have a decimal point (or period/dot) with decimal places. We may also include commas to separate thousands (say for a value of one billion). We may also want to have Max and Min values for the value being entered. I would like to include all of these features as part of this control.

This control is a superset of my previous control "uctTextField" (developed as part of the previous article). So you need to have "uctTextField.ascx" as part of your solution before proceeding with the new control. Let us start the development now.

Developing your own flexible NumericTextbox control: the beginning

Using the Solution Explorer, right click on your solution and choose Add New Item. Within the Add New Item dialog box, select Web User Control as the template, provide the name of the User Control as "uctNumericTextField" and hit Add.

Drag and drop the controls (and other stuff) onto your user control, so that it looks likes the following in the source mode:

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="uctNumericTextField.ascx.vb" Inherits="uctNumericTextField" %>
<%@ Register Src="uctTextField.ascx" TagName="uctTextField" TagPrefix="uc1" %>
<asp:Panel ID="pnlControl" runat="server"><uc1:uctTextField ID="utxtControl" runat="server" />
  
<asp:RegularExpressionValidator ID="regExpValidator" runat="server" ControlToValidate="utxtControl"
     
Display="None" ErrorMessage="[*name*] must be valid." ValidationExpression="^d+(?:.d{0,2})?$"></asp:RegularExpressionValidator>
  
<asp:CustomValidator ControlToValidate="utxtControl" ID="cstmValidator" runat="server" Display="None" ErrorMessage="Value not in range"></asp:CustomValidator></asp:Panel>
<asp:Label ID="lblInfo" runat="server" Text="TextField Numeric"></asp:Label>

According to the above source, you can understand that the entire control is again a part of the Panel control. Within the panel, I created two validators (a Regular Expression validator and a Custom Validator), uctTextField and a Label. Make sure that the path of "uctTextField.ascx" is set properly. The layout should look like the following in design mode (Fig 01):

Developing your own flexible NumericTextbox control: the skeleton

Once the design is completed, we need to start coding. In the code, I followed the following skeleton:

Imports System.ComponentModel

<ControlValueProperty("Text"), _
 
ValidationProperty("Text")> _
Partial Class uctNumericTextField
 
Inherits System.Web.UI.UserControl
.
.

#Region "Page Events"
.
.
  Public Overrides Sub Focus()
  Private Sub ApplyRegExpValString()
  Private Property RegExpValString() As String
  Public Property IncludeThousandsSeparator() As Boolean
  Public Property DecimalPlaces() As Integer
  Public Property MaxLength() As Integer
  Public Property MaxValue() As Decimal
  Public Property MinValue() As Decimal
  Public Property Text() As String
  Private Function UnFormattedValue(ByVal strValue As String) As String
  Private Function FormattedValue(ByVal strValue As String) As String
  Public Property ErrorText() As String
  Public Property Editable() As Boolean
  Public Property Required() As Boolean
  Public Property LabelTextValue() As String
  Public Property LabelTextAlign() As
  Public Property LabelTextVisible() As Boolean
  Public Property LabelTextWidth() As System.Web.UI.WebControls.Unit
  Public Property AutoPostBack() As Boolean
  Public Property CssClassTextBoxControl() As String
  Public Property CssClassLabelControl() As String
  Public Property CssClassLabelText() As String
  Public Property Tooltip() As String
  Public Property ValidationGroup() As String
.
.
End Class

I removed the code for clarity. Based on the discussion of the requirements in previous sections, I came up with the above list of properties, methods and events. I removed the TextChanged event from this control. If you need it, you can add it as explained in my previous article.

You could also observe that a few of the properties in the previous user control (uctTextField) also got repeated here. That is necessary as we need to map the same existing functionality of uctTextField to this control. You can modify the properties according to your naming conventions and standards. My intention is just to give you an idea of the list of features of the user control.

Developing your own flexible NumericTextbox control: coding events

I am currently using Page Events to simply maintain ViewState. The code is as follows:

#Region "Page Events"

  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   
If IsPostBack Then
     
ErrorText = ViewState.Item("ErrorText").ToString
     
Required = CType(ViewState.Item("Required"), Boolean)
     
DecimalPlaces = CType(ViewState.Item("DecimalPlaces"), Integer)
     
IncludeThousandsSeparator = CType(ViewState.Item("IncludeThousandsSeparator"), Boolean)
     
RegExpValString = ViewState.Item("RegExp").ToString
     
MaxValue = CType(ViewState.Item("MaxValue"), Decimal)
     
MinValue = CType(ViewState.Item("MinValue"), Decimal)
   
Else
     
Me.lblInfo.Visible = False
   
End If
 
End Sub

  Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
   
ViewState.Item("ErrorText") = ErrorText
   
ViewState.Item("Required") = Required
   
ViewState.Item("DecimalPlaces") = DecimalPlaces
   
ViewState.Item("IncludeThousandsSeparator") = IncludeThousandsSeparator
   
ViewState.Item("RegExp") = RegExpValString
   
ViewState.Item("MaxValue") = MaxValue
   
ViewState.Item("MinValue") = MinValue
 
End Sub

#End Region

The importance of "lblInfo" is worth mentioning at this moment. When a user control simply contains another user control as part of the design, it doesn't show up properly during design time (on ASPX). All the nested user controls look hidden, and the user would not be happy with an empty control. That's why I added "lblInfo" to show at design time that it is a numeric user control. At runtime it gets automatically hidden.

Apart from the events, I used a Focus method. When the control receives the focus, the cursor should be available in the text box. If the control is in read-only mode, it will not be able to receive any focus. It is defined as follows:

Public Overrides Sub Focus()
 
If Editable Then Me.utxtControl.Focus()
End Sub

You can observe that I am calling the focus method of "utxtControl" when this control receives the focus. The validation based on Max and Min values is handled as follows:

Protected Sub cstmValidator_ServerValidate(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs) Handles cstmValidator.ServerValidate
 
Dim value As Decimal = UnFormattedValue(args.Value)
 
If value > MaxValue Or value < MinValue Then
   
args.IsValid = False
   
cstmValidator.ErrorMessage = Me.ErrorText & " should be in between " & Me.MinValue & " and " & Me.MaxValue
 
Else
   
args.IsValid = True
 
End If
End Sub

Developing your own flexible NumericTextbox control: dealing with Regular Expressions

Our control needs to deal with Regular Expressions as we would like to have support for decimal places, commas and so forth. The regular expressions are applied as follows based on the properties set by the user:

Private Sub ApplyRegExpValString()
 
If IncludeThousandsSeparator Then
   
If DecimalPlaces > 0 Then
     
RegExpValString = "(?n:(^$?(?!0,?d)d{1,3}(?=(?<1>,)|(?<1>))(k<1>d{3})*(.d{0," & DecimalPlaces & "})?)$)"
   
Else
     
RegExpValString = "(?n:(^$?(?!0,?d)d{1,3}(?=(?<1>,)|(?<1>))(k<1>d{3})*)$)"
   
End If
 
Else
   
If DecimalPlaces > 0 Then
     
RegExpValString = "^d+(?:.d{0," & DecimalPlaces & "})?$"
   
Else
     
RegExpValString = "^d+?$"
   
End If
 
End If
End Sub

Private Property RegExpValString() As String
 
Get
   
Return m_strRegExp
 
End Get
 
Set(ByVal value As String)
   
m_strRegExp = value
   
Me.regExpValidator.ValidationExpression = value
 
End Set
End Property

A few of the regular expressions which are most commonly used for these types of scenarios are as follows

  • (?n:(^$?(?!0,?d)d{1,3}(?=(?<1>,)|(?<1>))(k<1>d{3})*(.dd)?)$) - for $,comma,compulsory 2 dig dec
  • (?n:(^$?(?!0,?d)d{1,3}(?=(?<1>,)|(?<1>))(k<1>d{3})*)$) - for $, comma, no dig dec
  • (?n:(^$?(?!0,?d)d{1,3}(?=(?<1>,)|(?<1>))(k<1>d{3})*(.d{0,2})?)$) - for $, comma, option 2 dig dec
  • ^d+(?:.d{0,2})?$ - without $, no comma, optional 2 dig dec
  • ^d+?$ - without $, no comma, no dec

Developing your own flexible NumericTextbox control: properties to retrieve values

We may need to work with a few more properties apart from the Text property. A few applications need the value to be available with or without formatting. The following are the properties that support all of these scenarios:

<EditorBrowsable(EditorBrowsableState.Always), _
   
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), _
   
Bindable(True), Browsable(True), Category("Common")> _
  Public Property Text() As String
   
Get
     
Return UnFormattedValue(Me.utxtControl.Text)
   
End Get
   
Set(ByVal Value As String)
     
Me.utxtControl.Text = FormattedValue(Value)
     
End Set
  End Property

  Private Function UnFormattedValue(ByVal strValue As String) As String
   
strValue = strValue.Replace("$"c, String.Empty).Replace(","c, String.Empty)
   
Return strValue
 
End Function

  Private Function FormattedValue(ByVal strValue As String) As String
   
If Me.IncludeThousandsSeparator Then
     
If Me.DecimalPlaces > 0 Then
       
Dim strDecFormat As String = "".PadLeft(Me.DecimalPlaces, "0"c)
       
Return String.Format("{0:#,##0." & strDecFormat & "}", CType(UnFormattedValue(strValue), Decimal))
     
Else
       
Return String.Format("{0:#,##0}", CType(UnFormattedValue(strValue), Decimal))
     
End If
   
Else
     
If Me.DecimalPlaces > 0 Then
       
Dim strDecFormat As String = "".PadLeft(Me.DecimalPlaces, "0"c)
        
Return String.Format("{0:#0." & strDecFormat & "}", CType(UnFormattedValue(strValue), Decimal))
     
Else
       
Return strValue
     
End If
   
End If

  End Function

Developing your own flexible NumericTextbox control: new properties added

The following are the new properties added to the control (apart from the properties added from previous uctTextField control):

<Category("Common")> _
Public Property IncludeThousandsSeparator() As Boolean
 
Get
   
Return m_blnIncludeThousandsSeparator
 
End Get
 
Set(ByVal value As Boolean)
   
m_blnIncludeThousandsSeparator = value
   
ApplyRegExpValString()
 
End Set
End Property

<Category("Common")> _
Public Property DecimalPlaces() As Integer
 
Get
   
Return m_intDecimalPlaces
 
End Get
 
Set(ByVal value As Integer)
   
If value < 0 Or value > 5 Then Throw New ApplicationException("Invalid Decimal specification")
   
If DecimalPlaces <> value Then
     
m_intDecimalPlaces = value
     
ApplyRegExpValString()
   
End If
 
End Set
End Property

<Category("Common")> _
Public Property MaxLength() As Integer
  Get
    Return Me.utxtControl.MaxLength
 
End Get
 
Set(ByVal value As Integer)
   
Me.utxtControl.MaxLength = value
 
End Set
End Property

<Category("Common")> _
Public Property MaxValue() As Decimal
 
Get
   
Return m_decMaxValue
 
End Get
 
Set(ByVal value As Decimal)
   
m_decMaxValue = value
  
End Set
End Property

<Category("Common")> _
Public Property MinValue() As Decimal
 
Get
   
Return m_decMinValue
 
End Get
 
Set(ByVal value As Decimal)
   
m_decMinValue = value
 
End Set
End Property

I hope you enjoyed the article and any suggestions, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com

blog comments powered by Disqus
ASP.NET ARTICLES

- Implementing ASP.NET 4.0 Page.MetaDescriptio...
- ASP.Net Development Tips
- Intro to Sessions in ASP.Net
- Google Maps API Introduction in ASP.NET usin...
- Creating an ASP.NET 3.5 Gridview Image Galle...
- Encrypt QueryString in ASP.NET 3.5 using VB....
- ASP.NET 3.5 Drop Down List Controls
- Connect to Access Database with ASP.Net
- Secure Audio Streaming with ASP.Net and Flash
- Dynamic Sitemap and Navigation in ASP.Net
- Implement Gzip and Deflate Compression in AS...
- Run ASP.Net in Ubuntu with Apache
- ASP.Net Mono Website Contact Forms
- ASP.Net URL Rewriting Methods
- Murach`s ASP.NET 4 Web Programming with C# 2...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 6 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials