Petite classe permettant la saisie de montant en respectant les contraintes spécifiques liées aux cultures. (Symbol, nombres de décimal)
Source / Exemple :
#region Using
using System;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
#endregion Using
namespace CS.TextBoxes
{
[ToolboxBitmap(typeof(TextBox))]
/// <summary>
/// Provides a control allowing typing only currency values.
/// This control supports Culture-specific constraints.
/// </summary>
public class CurrencyTextBox : TextBox
{
#region Fields
private CultureInfo _culture = System.Globalization.CultureInfo.CurrentUICulture;
private int _digitsCount = System.Globalization.CultureInfo.CurrentUICulture.NumberFormat.CurrencyDecimalDigits;
private string separator;
private bool overridesCulture;
#endregion Fields
#region Constructors
/// <summary>
/// Initialiazes a new instance of <see cref="CurrencyTextBox"/>.
/// </summary>
public CurrencyTextBox()
{
separator = _culture.NumberFormat.CurrencyDecimalSeparator;
}
#endregion Constructors
#region Key events
protected override void OnKeyPress(KeyPressEventArgs e)
{
int sepIndex = this.Text.IndexOf(separator);
double val = TryParseCurrency(this.Text, !overridesCulture);
int digits = CountDigits();
if (char.IsNumber(e.KeyChar) || char.IsControl(e.KeyChar))
{
if (digits >= _digitsCount && SelectionStart > sepIndex + digits) //we have not reached the max digits
{
e.Handled = true;
}
else
{
if (char.IsNumber((char)e.KeyChar) && val == 0)
{
this.Text = e.KeyChar.ToString(_culture);
this.SelectionStart += 1;
e.Handled = true;
}
else //Value was not 0
base.OnKeyPress(e);
}
}
else
{
//We entered the separator char
if (separator.StartsWith(e.KeyChar.ToString(_culture)))
this.SelectionStart = this.Text.IndexOf(separator) + 1;
//We entered the negative char
else if (e.KeyChar == '-')
this.Text = (-val).ToString(_culture);
e.Handled = true;
}
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
int cursorPos = this.SelectionStart;
if (cursorPos < 0)
return;
int count = CountGroups(this.Text, _culture);
base.Text = DoubleToStringCurrency(TryParseCurrency(this.Text, !overridesCulture), !overridesCulture);
// adujst caret position
this.SelectionStart = cursorPos + CountGroups(this.Text, _culture) - count;
}
#endregion Key events
#region Helpers
private int CountDigits()
{
int sepIndex = this.Text.IndexOf(separator) + 1; //index start to 0
return IsCurrencySymbolBefore ? this.Text.Trim().Length - sepIndex : this.Text.Trim().Length - 1 - sepIndex;
}
private string DoubleToStringCurrency(double d, bool useCultureFormat)
{
if (useCultureFormat)
{
return d.ToString("C", _culture);
}
else
{
return d.ToString("C" + _digitsCount.ToString(_culture));
}
}
private double TryParseCurrency(string text, bool useCultureFormat)
{
double d;
if( useCultureFormat)
{
double.TryParse(text, System.Globalization.NumberStyles.Currency, _culture, out d);
}
else
{
NumberStyles s = NumberStyles.AllowThousands | NumberStyles.AllowTrailingWhite | NumberStyles.AllowDecimalPoint | NumberStyles.AllowCurrencySymbol;
double.TryParse(text, s, _culture, out d);
}
return d;
}
private bool IsCurrencySymbolBefore
{
get
{
return char.IsSymbol(this.Text[0]);
}
}
/// <summary>
/// Coint number of groups in value.
/// </summary>
/// <param name="value"></param>
/// <param name="format">CultureInfo containing number format</param>
/// <returns>Groups count.</returns>
private static int CountGroups(string value, CultureInfo format)
{
int count = 0;
NumberFormatInfo nfi = format.NumberFormat;
for(int i = 0; i < value.Length - 1 ; ++i)
if(value[i] == nfi.NumberGroupSeparator[0])
count++;
return count;
}
#endregion Helpers
#region Properties
/// <summary>
/// Gets or sets the culture associated to textbox.
/// </summary>
public System.Globalization.CultureInfo Culture
{
get { return this._culture; }
set
{
double d = TryParseCurrency(this.Text, !overridesCulture);
if (value.IsNeutralCulture)
value = CultureInfo.InvariantCulture;
this._culture = value;
_digitsCount = value.NumberFormat.CurrencyDecimalDigits;
separator = _culture.NumberFormat.CurrencyDecimalSeparator;
this.Text = DoubleToStringCurrency(d, !overridesCulture);
}
}
/// <summary>
/// Gets or sets the number of decimals after separator.
/// </summary>
public int DigitsCount
{
get { return this._digitsCount; }
set
{
this._digitsCount = value;
overridesCulture = value != this._culture.NumberFormat.CurrencyDecimalDigits;
}
}
/// <summary>
/// Ovverides Text property to format string.
/// </summary>
public new string Text
{
get
{
return base.Text;
}
set
{
double empty = 0;
base.Text = value.Trim().Length > 0 ? value : empty.ToString("C", _culture);
this.SelectionStart = Convert.ToInt32(IsCurrencySymbolBefore);
}
}
/// <summary>
/// Gets or sets the numeric value of the represented string.
/// </summary>
public double Value
{
get
{
return TryParseCurrency(this.Text, !overridesCulture);
}
set
{
base.Text = value.ToString();
this.SelectionStart = IsCurrencySymbolBefore ? 1 : 0;
}
}
#endregion Properties
}
}
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.