Currency textbox - textbox de saisie de montant.

Contenu du snippet

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

	}
}

A voir également

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.