Click here to Skip to main content
15,888,116 members
Articles / Web Development / ASP.NET
Article

A Localizable Currency TextBox

Rate me:
Please Sign up or sign in to vote.
4.41/5 (25 votes)
23 Sep 20054 min read 210.1K   2.3K   55   51
A localizable Currency textbox control.

Sample Image

Introduction

My attempts to find a suitable control for displaying and editing correctly formatted currency values that could be bound to a decimal value were in vain, so I set about creating my first custom web control.

Note: The download also includes a PercentBox and NumberBox control which use the same principles.

Control Requirements

The first step was to define the essential requirements for the control.

  • Allow databinding to a decimal value.
  • Display the value as currency text, formatted in accordance with the current culture.
  • Display negative values in a different colour.
  • Allow only valid data entry.
  • Perform the work associated with validating input and formatting currency values on the client side.

Starting Out

While the control renders as a text box <INPUT type="text" ...>, inheriting from System.Web.UI.WebControls.TextBox would have required many properties to be hidden, so the control inherits from System.Web.UI.WebControls.WebControl and implements IPostBackDataHandler.

Properties

Eleven public properties are added to the base class to control its appearance:

  • Alignment: Sets the alignment of text in the control (the default is Right).
  • Amount: The decimal value to be bound to the control. The value is stored in ViewState and the implementation of IPostBackDataHandler ensures the AmountChanged event is raised when appropriate.
    C#
    [
    DefaultValue(typeof(decimal),"0"),
    Category("Appearance"),
    Bindable(true),
    Description("The amount displayed in the control")
    ]
    public decimal Amount
    {
      get
      {
        // Check if a value has been assigned
        object amount = ViewState["amount"];
        if (amount == null)
          // Return the default
          return 0M;
        else
          // Return the value
          return (decimal)amount;
      }
      set
      {
        ViewState["amount"] = value;
        // Set the text colour
        if (value < 0)
          base.ForeColor = NegativeColor;
        else
          base.ForeColor = PositiveColor;
      }
    }
  • MinAmount: Sets the minimum amount which can be entered by the user.
  • MaxAmount: Sets the maximum amount which can be entered by the user.
  • NegativeColor: Sets the colour to display if the Amount is negative (<0).
    C#
    [
    DefaultValue(typeof(Color),"Red"),
    Category("Appearance"),
    Bindable(true),
    Description("The colour of negative currency values")
    ]
    public Color NegativeColor
    {
      get
      {
        return _NegativeColor;
      }
      set
      {
        _NegativeColor = value;
        // Set the controls ForeColor if appropriate
        if (Amount < 0)
          base.ForeColor = value;
      }
    }
  • OnBlur, OnFocus and OnKeyPress: The control outputs JavaScript code for these HTML events, and these properties allow additional scripts to be assigned.
  • PositiveColor: Sets the colour to display if the Amount is positive.
  • Precision: The number of decimal places that the formatted amount will display.
  • Text: A readonly property which returns the Amount formatted in accordance with the current culture.

In addition, the base class ForeColor property is hidden to implement it as readonly (because its colour is set using the PositiveColor and NegativeColor properties).

Rendering the Control

A WebControl, by default, renders as <SPAN>. To render as a textbox <INPUT>, we must first override TagKey.

C#
protected override HtmlTextWriterTag TagKey
{
  get
  {
    return HtmlTextWriterTag.Input;
  }
}

and then add attributes by overriding AddAttributesToRender.

C#
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
  base.AddAttributesToRender(writer);
  // Add attributes necessary to display an text control
  writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
  writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
  writer.AddStyleAttribute("text-align", Alignment.ToString());
  // Add user defined attributes to control colour formatting
  writer.AddAttribute("negativeColor", NegativeColor.Name);
  if (PositiveColor != Color.Empty)
  {
    writer.AddAttribute("positiveColor", PositiveColor.Name);
  }
  // Add client side event handlers
  writer.AddAttribute("onkeypress", "EnsureNumeric()");
  writer.AddAttribute("onfocus", "FormatAsDecimal(this)");
  writer.AddAttribute("onblur", "FormatAsCurrency(this)");
}

Two user defined attributes are added to the rendered control, positiveColor and negativeColor. These two attributes are read by the client-side script to set the colour of the text depending on its value. In addition, three client side events are assigned to script functions as discussed below.

Client Side Scripts

The base class OnPreRender method is overridden to get the current culture's NumberFormat. Then it is checked if the scripts have been registered, and if not, code is called to construct them using the NumberFormat, and finally register them.

C#
protected override void OnPreRender(EventArgs e)
{
  // Get the number format of the current culture
  NumberFormatInfo format = Thread.CurrentThread.CurrentCulture.NumberFormat;
  // Register the EnsureNumeric script
  if (!Page.IsClientScriptBlockRegistered("EnsureNumeric"))
  {
    Page.RegisterClientScriptBlock("EnsureNumeric",EnsureNumericScript(format));
  }
  ...........

Five script functions are registered.

  • EnsureNumeric() is assigned to the OnKeyPress event and limits keyboard entry to valid input.
  • FormatCurrencyAsDecimal() is assigned to the OnFocus event. It calls the CurrencyToDecimal() function and formats its text based on the returned value.
  • FormatDecimalAsCurrency() is assigned to the OnBlur event. It calls the DecimalToCurrency() function and formats its text based on the returned value.
  • CurrencyToDecimal() parses a currency string to a decimal value.
  • DecimalToCurrency() formats a decimal value as a currency string.

The code used to generate these scripts is too lengthy to be included here but the download includes a htm file explaining the methodology I used.

Using the Control

  • Download and build the Web Control Library project.
  • Create a new ASP.NET Web Application project and add the control to the toolbox.
  • Drag the control onto a form and set some properties.
  • In the ASP.NET Web Application project Web.Config file, modify the globalization section to set a specific culture (e.g., culture="fr-FR" (for French-France) or culture="id-ID" (for Indonesian-Indonesia) etc.). Note that you must use a specific culture, not a neutral culture.
    XML
    <globalization
      requestEncoding="utf-8"
      responseEncoding="utf-8"
      culture="fr-FR"
    />
    
  • Run the project.
  • The Amount property will be displayed in accordance with the culture you specify in the Web.Config file. Tab into the control and the text will be parsed to a decimal value.
  • Enter a numeric value and tab out. The text will be formatted back to a currency string with the colour set in accordance with PositiveColor or NegativeColor.

Note that when entering data, only numbers (0-9), the minus sign and the decimal separator (if appropriate) can be entered. Some languages such as Indonesian do not have decimal digits, in which case a decimal separator cannot be entered. Note also that the decimal separator for many languages (European) is a comma, not a decimal point.

History

  • v1.0 - 08 June 2005 - Created.
  • v1.1 - 04 August 2005
    • Additional properties for MinAmount, MaxAmount, OnBlur, OnFocus, OnKeyPress and Precision added.
    • Scripts amended.
    • NumberBox and PercentBox added to the project.
  • v1.2 - 20 September 2005
    • Scripts amended to validate minimum and maximum values.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralData binding Pin
Bacos30-Nov-05 2:17
Bacos30-Nov-05 2:17 
GeneralRe: Data binding Pin
Howard Richards5-Sep-09 13:50
Howard Richards5-Sep-09 13:50 
GeneralIt is not safe to do this! Pin
Mihai Nita25-Sep-05 12:36
Mihai Nita25-Sep-05 12:36 
GeneralRe: It is not safe to do this! Pin
Stephen Muecke26-Sep-05 14:11
Stephen Muecke26-Sep-05 14:11 
GeneralRe: It is not safe to do this! Pin
Mihai Nita26-Sep-05 22:51
Mihai Nita26-Sep-05 22:51 
GeneralRe: It is not safe to do this! Pin
Stephen Muecke27-Sep-05 15:59
Stephen Muecke27-Sep-05 15:59 
GeneralRe: It is not safe to do this! Pin
Mihai Nita27-Sep-05 18:57
Mihai Nita27-Sep-05 18:57 
GeneralRe: It is not safe to do this! Pin
Stephen Muecke29-Sep-05 14:21
Stephen Muecke29-Sep-05 14:21 
GeneralRe: It is not safe to do this! Pin
Mihai Nita10-Oct-05 0:28
Mihai Nita10-Oct-05 0:28 
GeneralRe: It is not safe to do this! Pin
Stephen Muecke11-Oct-05 14:00
Stephen Muecke11-Oct-05 14:00 
GeneralRe: It is not safe to do this! Pin
Member 8715876-Nov-09 10:11
Member 8715876-Nov-09 10:11 
QuestionAmounts + 00? Pin
Member 33215069-Sep-05 8:13
Member 33215069-Sep-05 8:13 
AnswerRe: Amounts + 00? Pin
Stephen Muecke20-Sep-05 0:32
Stephen Muecke20-Sep-05 0:32 
GeneralThank you very much! Pin
Member 131985828-Aug-05 17:34
Member 131985828-Aug-05 17:34 
QuestionDo you have an update? Pin
Marc Clifton24-Jul-05 11:43
mvaMarc Clifton24-Jul-05 11:43 
AnswerRe: Do you have an update? Pin
Stephen Muecke1-Aug-05 19:29
Stephen Muecke1-Aug-05 19:29 
GeneralRe: Do you have an update? Pin
Marc Clifton8-Aug-05 5:27
mvaMarc Clifton8-Aug-05 5:27 
GeneralRe: Do you have an update? Pin
Alex Shamin16-Aug-05 1:15
Alex Shamin16-Aug-05 1:15 
GeneralRe: Do you have an update? Pin
Stephen Muecke17-Aug-05 20:17
Stephen Muecke17-Aug-05 20:17 
QuestionHow to take away the currency sign? Pin
WilsonTeo17-Jul-05 15:59
WilsonTeo17-Jul-05 15:59 
AnswerRe: How to take away the currency sign? Pin
Stephen Muecke18-Jul-05 22:23
Stephen Muecke18-Jul-05 22:23 
GeneralRe: How to take away the currency sign? Pin
WilsonTeo31-Jul-05 17:50
WilsonTeo31-Jul-05 17:50 
GeneralRe: How to take away the currency sign? Pin
Stephen Muecke1-Aug-05 19:31
Stephen Muecke1-Aug-05 19:31 
AnswerRe: How to take away the currency sign? Pin
Mihai Nita25-Sep-05 12:28
Mihai Nita25-Sep-05 12:28 
GeneralRe: How to take away the currency sign? Pin
Stephen Muecke26-Sep-05 13:44
Stephen Muecke26-Sep-05 13:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.