190 lines
4.5 KiB
C#
190 lines
4.5 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Windows.Forms;
|
|
using System.Globalization;
|
|
|
|
|
|
namespace Aga.Controls
|
|
{
|
|
/// <summary>
|
|
/// Restricts the entry of characters to digits, the negative sign,
|
|
/// the decimal point, and editing keystrokes (backspace).
|
|
/// It does not handle the AltGr key so any keys that can be created in any
|
|
/// combination with AltGr these are not filtered
|
|
/// </summary>
|
|
public class NumericTextBox : TextBox
|
|
{
|
|
private const int WM_PASTE = 0x302;
|
|
private NumberStyles numberStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
|
|
|
|
/// <summary>
|
|
/// Restricts the entry of characters to digits, the negative sign,
|
|
/// the decimal point, and editing keystrokes (backspace).
|
|
/// It does not handle the AltGr key
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
protected override void OnKeyPress(KeyPressEventArgs e)
|
|
{
|
|
base.OnKeyPress(e);
|
|
|
|
e.Handled = invalidNumeric(e.KeyChar);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Main method for verifying allowed keypresses.
|
|
/// This does not catch cut paste copy ... operations.
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
private bool invalidNumeric(char key)
|
|
{
|
|
bool handled = false;
|
|
|
|
NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat;
|
|
string decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
|
|
string negativeSign = numberFormatInfo.NegativeSign;
|
|
|
|
string keyString = key.ToString();
|
|
|
|
if (Char.IsDigit(key))
|
|
{
|
|
// Digits are OK
|
|
}
|
|
else if (AllowDecimalSeparator && keyString.Equals(decimalSeparator))
|
|
{
|
|
if (Text.IndexOf(decimalSeparator) >= 0)
|
|
{
|
|
handled = true;
|
|
}
|
|
}
|
|
else if (AllowNegativeSign && keyString.Equals(negativeSign))
|
|
{
|
|
if (Text.IndexOf(negativeSign) >= 0)
|
|
{
|
|
handled = true;
|
|
}
|
|
}
|
|
else if (key == '\b')
|
|
{
|
|
// Backspace key is OK
|
|
}
|
|
else if ((ModifierKeys & (Keys.Control)) != 0)
|
|
{
|
|
// Let the edit control handle control and alt key combinations
|
|
}
|
|
else
|
|
{
|
|
// Swallow this invalid key and beep
|
|
handled = true;
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Method invoked when Windows sends a message.
|
|
/// </summary>
|
|
/// <param name="m">Message from Windows.</param>
|
|
/// <remarks>
|
|
/// This is over-ridden so that the user can not use
|
|
/// cut or paste operations to bypass the TextChanging event.
|
|
/// This catches ContextMenu Paste, Shift+Insert, Ctrl+V,
|
|
/// While it is generally frowned upon to override WndProc, no
|
|
/// other simple mechanism was apparent to simultaneously and
|
|
/// transparently intercept so many different operations.
|
|
/// </remarks>
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
// Switch to handle message...
|
|
switch (m.Msg)
|
|
{
|
|
case WM_PASTE:
|
|
{
|
|
// Get clipboard object to paste
|
|
IDataObject clipboardData = Clipboard.GetDataObject();
|
|
|
|
// Get text from clipboard data
|
|
string pasteText = (string)clipboardData.GetData(
|
|
DataFormats.UnicodeText);
|
|
|
|
// Get the number of characters to replace
|
|
int selectionLength = SelectionLength;
|
|
|
|
// If no replacement or insertion, we are done
|
|
if (pasteText.Length == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (selectionLength != 0)
|
|
{
|
|
base.Text = base.Text.Remove(SelectionStart, selectionLength);
|
|
}
|
|
|
|
bool containsInvalidChars = false;
|
|
foreach (char c in pasteText)
|
|
{
|
|
if (containsInvalidChars)
|
|
{
|
|
break;
|
|
}
|
|
else if (invalidNumeric(c))
|
|
{
|
|
containsInvalidChars = true;
|
|
}
|
|
}
|
|
|
|
if (!containsInvalidChars)
|
|
{
|
|
base.Text = base.Text.Insert(SelectionStart, pasteText);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
|
|
public int IntValue
|
|
{
|
|
get
|
|
{
|
|
int intValue;
|
|
Int32.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out intValue);
|
|
return intValue;
|
|
}
|
|
}
|
|
|
|
public decimal DecimalValue
|
|
{
|
|
get
|
|
{
|
|
decimal decimalValue;
|
|
Decimal.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out decimalValue);
|
|
return decimalValue;
|
|
}
|
|
}
|
|
|
|
|
|
private bool allowNegativeSign;
|
|
[DefaultValue(true)]
|
|
public bool AllowNegativeSign
|
|
{
|
|
get { return allowNegativeSign; }
|
|
set { allowNegativeSign = value; }
|
|
}
|
|
|
|
private bool allowDecimalSeparator;
|
|
[DefaultValue(true)]
|
|
public bool AllowDecimalSeparator
|
|
{
|
|
get { return allowDecimalSeparator; }
|
|
set { allowDecimalSeparator = value; }
|
|
}
|
|
|
|
}
|
|
|
|
}
|