Wednesday, October 8, 2008

Global currencies and editing within a textbox

When dealing with invariant cultures, one potential problem is formatting the currency for the current culture correctly for edit within a text box.

A simple solution is to use the currency format string, which works great:

//Set the CurrentCulture to French in France.
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Console.WriteLine(i.ToString("c"));
Output: 100,00 F


This is great except for a simple problem when setting up an UI for editing this information. The text box will contain the currency symbol for the current culture. You want the currency to appear in the correct format for the user, but in some cases, not appear with the currency symbol.

So instead of getting 120.00 in the US, your user will have a box with $120.00, and in the case of the example 100,00 F instead of 100,00

Of course, if your only concerned with the US, or your application is concerned with a single currency symbol, you can always use the old standby:
string balanceForEdit = balanceForEdit.Replace("$", string.Empty);

If your requirement is to remove the currency symbol from the edit text box, while supporting any number of cultures, currencies, and their potential symbols here is a simple solution:

1. Clone the current NumberFormatInfo
2. Set the currency symbol to an empty string
3. Use this NumberFormatInfo class in your format string

Here is a working example:

private string FormatToGlobalCurrencyForEdit(decimal amount)
{
System.Globalization.NumberFormatInfo nfi = System.Globalization.NumberFormatInfo.CurrentInfo.Clone() as System.Globalization.NumberFormatInfo;

nfi.CurrencySymbol = string.Empty;

return string.Format(nfi, "{0:c}", amount);
}


Resources:
Globalization Step-by-Step

2 comments:

david morton said...

Great post, Chris. Concerning simplicity of code, however, couldn't the user just write:

decimal value = 1200.44M;
value.ToString("N2");

That would also yield "1,200.44", without the currency specifier.

Christopher Hardwick said...

David,

First, thanks for reading the blog. It's great when someone comments, because it shows someone is reading.

In your example, yes
decimal value = 1200.44M;
value.ToString("N2");

Would yeald the same result as my example, but other currencies are not limited to two decimal places in their precision. You should also consider that other cultures handle precision rounding differently.

By using the System.Globalization.NumberFormatInfo class, your sure that the resulting value will match the expected output, just without the currency symbol.

Take my example:
decimal i = 1000m;
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Console.WriteLine(i.ToString("c"));
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-AR");
Console.WriteLine(i.ToString("c"));

Output:
fr-FR:1 000,00 ?
es-AR:$ 1.000,00

If that doesn't make sense, or requires some additional information, please let me know.