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