External/Aga.Controls/NumericTextBox.cs
author sl
Thu, 01 Jan 2015 23:35:49 +0100
changeset 405 5715aefd2bcc
permissions -rw-r--r--
SharpDisplay: Migrating to new robust client scheme.
     1 using System;
     2 using System.ComponentModel;
     3 using System.Windows.Forms;
     4 using System.Globalization;
     5 
     6 
     7 namespace Aga.Controls
     8 {
     9 	/// <summary>
    10 	/// Restricts the entry of characters to digits, the negative sign,
    11 	/// the decimal point, and editing keystrokes (backspace).
    12 	/// It does not handle the AltGr key so any keys that can be created in any
    13 	/// combination with AltGr these are not filtered
    14 	/// </summary>
    15 	public class NumericTextBox : TextBox
    16 	{
    17 		private const int WM_PASTE = 0x302;
    18 		private NumberStyles numberStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    19 
    20 		/// <summary>
    21 		/// Restricts the entry of characters to digits, the negative sign,
    22 		/// the decimal point, and editing keystrokes (backspace).
    23 		/// It does not handle the AltGr key
    24 		/// </summary>
    25 		/// <param name="e"></param>
    26 		protected override void OnKeyPress(KeyPressEventArgs e)
    27 		{
    28 			base.OnKeyPress(e);
    29 
    30 			e.Handled = invalidNumeric(e.KeyChar);
    31 		}
    32 
    33 
    34 		/// <summary>
    35 		/// Main method for verifying allowed keypresses.
    36 		/// This does not catch cut paste copy ... operations.
    37 		/// </summary>
    38 		/// <param name="key"></param>
    39 		/// <returns></returns>
    40 		private bool invalidNumeric(char key)
    41 		{
    42 			bool handled = false;
    43 
    44 			NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat;
    45 			string decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
    46 			string negativeSign = numberFormatInfo.NegativeSign;
    47 
    48 			string keyString = key.ToString();
    49 
    50 			if (Char.IsDigit(key))
    51 			{
    52 				// Digits are OK
    53 			}
    54 			else if (AllowDecimalSeparator && keyString.Equals(decimalSeparator))
    55 			{
    56 				if (Text.IndexOf(decimalSeparator) >= 0)
    57 				{
    58 					handled = true;
    59 				}
    60 			}
    61 			else if (AllowNegativeSign && keyString.Equals(negativeSign))
    62 			{
    63 				if (Text.IndexOf(negativeSign) >= 0)
    64 				{
    65 					handled = true;
    66 				}
    67 			}
    68 			else if (key == '\b')
    69 			{
    70 				// Backspace key is OK
    71 			}
    72 			else if ((ModifierKeys & (Keys.Control)) != 0)
    73 			{
    74 				// Let the edit control handle control and alt key combinations
    75 			}
    76 			else
    77 			{
    78 				// Swallow this invalid key and beep
    79 				handled = true;
    80 			}
    81 			return handled;
    82 		}
    83 
    84 
    85 		/// <summary>
    86 		/// Method invoked when Windows sends a message.
    87 		/// </summary>
    88 		/// <param name="m">Message from Windows.</param>
    89 		/// <remarks>
    90 		/// This is over-ridden so that the user can not use
    91 		/// cut or paste operations to bypass the TextChanging event.
    92 		/// This catches ContextMenu Paste, Shift+Insert, Ctrl+V,
    93 		/// While it is generally frowned upon to override WndProc, no
    94 		/// other simple mechanism was apparent to simultaneously and
    95 		/// transparently intercept so many different operations.
    96 		/// </remarks>
    97 		protected override void WndProc(ref Message m)
    98 		{
    99 			// Switch to handle message...
   100 			switch (m.Msg)
   101 			{
   102 				case WM_PASTE:
   103 					{
   104 						// Get clipboard object to paste
   105 						IDataObject clipboardData = Clipboard.GetDataObject();
   106 
   107 						// Get text from clipboard data
   108 						string pasteText = (string)clipboardData.GetData(
   109 								DataFormats.UnicodeText);
   110 
   111 						// Get the number of characters to replace
   112 						int selectionLength = SelectionLength;
   113 
   114 						// If no replacement or insertion, we are done
   115 						if (pasteText.Length == 0)
   116 						{
   117 							break;
   118 						}
   119 						else if (selectionLength != 0)
   120 						{
   121 							base.Text = base.Text.Remove(SelectionStart, selectionLength);
   122 						}
   123 
   124 						bool containsInvalidChars = false;
   125 						foreach (char c in pasteText)
   126 						{
   127 							if (containsInvalidChars)
   128 							{
   129 								break;
   130 							}
   131 							else if (invalidNumeric(c))
   132 							{
   133 								containsInvalidChars = true;
   134 							}
   135 						}
   136 
   137 						if (!containsInvalidChars)
   138 						{
   139 							base.Text = base.Text.Insert(SelectionStart, pasteText);
   140 						}
   141 
   142 						return;
   143 					}
   144 
   145 			}
   146 			base.WndProc(ref m);
   147 		}
   148 
   149 
   150 		public int IntValue
   151 		{
   152 			get
   153 			{
   154 				int intValue;
   155 				Int32.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out intValue);
   156 				return intValue;
   157 			}
   158 		}
   159 
   160 		public decimal DecimalValue
   161 		{
   162 			get
   163 			{
   164 				decimal decimalValue;
   165 				Decimal.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out decimalValue);
   166 				return decimalValue;
   167 			}
   168 		}
   169 
   170 
   171 		private bool allowNegativeSign;
   172 		[DefaultValue(true)]
   173 		public bool AllowNegativeSign
   174 		{
   175 			get { return allowNegativeSign; }
   176 			set { allowNegativeSign = value; }
   177 		}
   178 
   179 		private bool allowDecimalSeparator;
   180 		[DefaultValue(true)]
   181 		public bool AllowDecimalSeparator
   182 		{
   183 			get { return allowDecimalSeparator; }
   184 			set { allowDecimalSeparator = value; }
   185 		}
   186 
   187 	}
   188 
   189 }