我有一个windows窗体应用程序与一个文本框控件,我想只接受整数值。在过去,我通过重载KeyPress事件并删除不符合规范的字符来进行这种验证。我已经看了MaskedTextBox控件,但我想一个更通用的解决方案,可以与也许正则表达式,或依赖于其他控件的值。
理想情况下,按下非数字字符要么不产生结果,要么立即向用户提供关于无效字符的反馈。
我有一个windows窗体应用程序与一个文本框控件,我想只接受整数值。在过去,我通过重载KeyPress事件并删除不符合规范的字符来进行这种验证。我已经看了MaskedTextBox控件,但我想一个更通用的解决方案,可以与也许正则表达式,或依赖于其他控件的值。
理想情况下,按下非数字字符要么不产生结果,要么立即向用户提供关于无效字符的反馈。
当前回答
这是一个简单的独立的Winforms自定义控件,从标准的TextBox派生而来,只允许System。Int32输入(它可以很容易地适用于其他类型,如System。Int64,等等)。它支持复制/粘贴操作和负数:
public class Int32TextBox : TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
NumberFormatInfo fi = CultureInfo.CurrentCulture.NumberFormat;
string c = e.KeyChar.ToString();
if (char.IsDigit(c, 0))
return;
if ((SelectionStart == 0) && (c.Equals(fi.NegativeSign)))
return;
// copy/paste
if ((((int)e.KeyChar == 22) || ((int)e.KeyChar == 3))
&& ((ModifierKeys & Keys.Control) == Keys.Control))
return;
if (e.KeyChar == '\b')
return;
e.Handled = true;
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_PASTE = 0x0302;
if (m.Msg == WM_PASTE)
{
string text = Clipboard.GetText();
if (string.IsNullOrEmpty(text))
return;
if ((text.IndexOf('+') >= 0) && (SelectionStart != 0))
return;
int i;
if (!int.TryParse(text, out i)) // change this for other integer types
return;
if ((i < 0) && (SelectionStart != 0))
return;
}
base.WndProc(ref m);
}
2017年更新:我的第一个答案有一些问题:
你可以输入一个比给定类型的整数更长的值(例如2147483648大于Int32.MaxValue); 更一般地说,对于输入的结果没有真正的验证; 它只处理int32,你必须写特定的TextBox衍生控件为每种类型(Int64等)
所以我提出了另一个更通用的版本,它仍然支持复制/粘贴,+和-号等。
public class ValidatingTextBox : TextBox
{
private string _validText;
private int _selectionStart;
private int _selectionEnd;
private bool _dontProcessMessages;
public event EventHandler<TextValidatingEventArgs> TextValidating;
protected virtual void OnTextValidating(object sender, TextValidatingEventArgs e) => TextValidating?.Invoke(sender, e);
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (_dontProcessMessages)
return;
const int WM_KEYDOWN = 0x100;
const int WM_ENTERIDLE = 0x121;
const int VK_DELETE = 0x2e;
bool delete = m.Msg == WM_KEYDOWN && (int)m.WParam == VK_DELETE;
if ((m.Msg == WM_KEYDOWN && !delete) || m.Msg == WM_ENTERIDLE)
{
DontProcessMessage(() =>
{
_validText = Text;
_selectionStart = SelectionStart;
_selectionEnd = SelectionLength;
});
}
const int WM_CHAR = 0x102;
const int WM_PASTE = 0x302;
if (m.Msg == WM_CHAR || m.Msg == WM_PASTE || delete)
{
string newText = null;
DontProcessMessage(() =>
{
newText = Text;
});
var e = new TextValidatingEventArgs(newText);
OnTextValidating(this, e);
if (e.Cancel)
{
DontProcessMessage(() =>
{
Text = _validText;
SelectionStart = _selectionStart;
SelectionLength = _selectionEnd;
});
}
}
}
private void DontProcessMessage(Action action)
{
_dontProcessMessages = true;
try
{
action();
}
finally
{
_dontProcessMessages = false;
}
}
}
public class TextValidatingEventArgs : CancelEventArgs
{
public TextValidatingEventArgs(string newText) => NewText = newText;
public string NewText { get; }
}
对于Int32,你可以从它导出,像这样:
public class Int32TextBox : ValidatingTextBox
{
protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
{
e.Cancel = !int.TryParse(e.NewText, out int i);
}
}
或w/o派生,使用新的textvalididating事件,像这样:
var vtb = new ValidatingTextBox();
...
vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);
但它的优点是它适用于任何字符串和任何验证例程。
其他回答
你可以使用TextChanged/ Keypress事件,使用正则表达式过滤数字,并采取一些行动。
我已经为各种验证创建了一个可重用的文本框扩展类,并考虑共享它。
您所需要做的就是引发一个TextChange事件,然后调用Validate方法。它是这样的:
private void tbxAmount_TextChanged(object sender, EventArgs e)
{
tbxAmount.Validate(TextValidator.ValidationType.Amount);
}
下面是扩展类:
public static class TextValidator
{
public enum ValidationType
{
Amount,
Integer
}
/// <summary>
/// Validate a textbox on text change.
/// </summary>
/// <param name="tbx"></param>
/// <param name="validationType"></param>
public static void Validate(this TextBox tbx, ValidationType validationType)
{
PerformValidation(tbx, validationType);
tbx.Select(tbx.Text.Length, 0);
}
private static void PerformValidation(this TextBox tbx, ValidationType validationType)
{
char[] enteredString = tbx.Text.ToCharArray();
switch (validationType)
{
case ValidationType.Amount:
tbx.Text = AmountValidation(enteredString);
break;
case ValidationType.Integer:
tbx.Text = IntegerValidation(enteredString);
break;
default:
break;
}
tbx.SelectionStart = tbx.Text.Length;
}
private static string AmountValidation(char[] enteredString)
{
string actualString = string.Empty;
int count = 0;
foreach (char c in enteredString.AsEnumerable())
{
if (count >= 1 && c == '.')
{ actualString.Replace(c, ' '); actualString.Trim(); }
else
{
if (Char.IsDigit(c))
{
actualString = actualString + c;
}
if (c == '.')
{
actualString = actualString + c; count++;
}
else
{
actualString.Replace(c, ' ');
actualString.Trim();
}
}
}
return actualString;
}
private static string IntegerValidation(char[] enteredString)
{
string actualString = string.Empty;
foreach (char c in enteredString.AsEnumerable())
{
if (Char.IsDigit(c))
{
actualString = actualString + c;
}
else
{
actualString.Replace(c, ' ');
actualString.Trim();
}
}
return actualString;
}
}
你可以在这里找到完整的代码
尝试一个MaskedTextBox。它采用一种简单的掩码格式,这样你就可以将输入限制为数字或日期之类的。
在文本框中简单地使用此代码:
private void textBox1_TextChanged(object sender, EventArgs e)
{
double parsedValue;
if (!double.TryParse(textBox1.Text, out parsedValue))
{
textBox1.Text = "";
}
}
我在CodePlex上做了一些东西。
它通过拦截TextChanged事件来工作。如果结果是一个好的数字,它将被存储。如果是错误的,最后的好值将恢复。源代码有点太大,不适合在这里发布,但这里有一个指向处理此逻辑核心的类的链接。