KeyPress事件中用e.Handled=true拦截非数字键是最快最轻量的方式,仅对可打印字符生效,需手动允许负号、小数点和退格;Delete等控制键需用PreviewKeyDown+SuppressKeyPress处理;最终内容校验应依赖TextChanged+正则。

TextBox.KeyPress 事件里用 e.Handled = true 拦截非数字键
直接在 KeyPress 事件中判断 e.KeyChar,是最快、最轻量的拦截方式。它发生在字符生成阶段,不干扰焦点、不触发文本变更逻辑,适合纯输入过滤。
- 只对可打印字符生效,
Backspace、Delete、Tab、Enter等控制键默认不会触发KeyPress,所以无需额外放行——但如果你需要支持退格和小数点,就得手动加判断 -
e.KeyChar是char类型,用char.IsDigit(e.KeyChar)只能识别 ASCII 数字(0–9),无法匹配全角数字或带符号场景 - 想允许负号、小数点、退格?得写成:
if (!char.IsDigit(e.KeyChar) && e.KeyChar != '-' && e.KeyChar != '.' && e.KeyChar != '\b') { e.Handled = true; }注意:负号必须限定在开头,小数点需防重复,这些得靠TextChanged配合校验,KeyPress单独搞不定
用 PreviewKeyDown + e.SuppressKeyPress 处理 Delete/Arrow 等键
KeyPress 抓不到 Delete、方向键、Home/End,如果用户选中文本后按 Delete,或者用方向键移动光标再输入,纯 KeyPress 就会漏掉。这时得上 PreviewKeyDown。
-
PreviewKeyDown在按键消息分发前触发,能捕获所有键,包括Keys.Delete、Keys.Back - 要阻止行为,不能设
e.Handled(它不生效),得用e.SuppressKeyPress = true - 注意:一旦设了
SuppressKeyPress = true,后续的KeyDown和KeyPress都不会触发,所以别在同一个 TextBox 上又绑KeyDown又绑PreviewKeyDown,容易互相覆盖 - 典型误操作:把
Keys.OemPeriod当作小数点——实际应判Keys.Decimal(数字小键盘点)和Keys.OemPeriod(主键盘点),两者 keycode 不同
正则 + TextChanged 校验比拦截更可靠,但有副作用
用 KeyPress 或 PreviewKeyDown 拦截,本质是“预测用户想输什么”,但用户可能粘贴、拖拽、用语音输入——这些绕过所有按键事件。真要保证内容干净,最终还得靠 TextChanged + 正则清洗。
- 示例:只留数字、负号、小数点,且负号只能在开头,小数点最多一个
private void textBox1_TextChanged(object sender, EventArgs e) {<br> string newText = Regex.Replace(textBox1.Text, @"[^0-9.-]", "");<br> if (newText.Count(c => c == '.') > 1 || newText.Count(c => c == '-') > 1) {<br> newText = Regex.Replace(newText, @"(?<=\.)[.-]", "");<br> }<br> if (newText.Length > 0 && newText[0] != '-' && newText.Contains("-")) {<br> newText = newText.Replace("-", "");<br> }<br> if (textBox1.Text != newText) {<br> textBox1.Text = newText;<br> textBox1.SelectionStart = textBox1.Text.Length;<br> } - 副作用明显:频繁修改
Text会重置光标位置,用户正在中间编辑时会被“弹”到末尾;如果没同步维护SelectionStart,体验极差 - 性能上,每次输入都跑正则+字符串重建,对长文本或高频输入(比如实时搜索框)有卡顿风险
WPF 的 TextBox 和 WinForms 行为完全不同
WinForms 的 KeyPress / PreviewKeyDown 机制在 WPF 里根本不存在。WPF 用的是路由事件 + PreviewTextInput + PreviewKeyDown 组合,而且默认不处理中文输入法的预编辑状态。
- WPF 中,
PreviewTextInput对应的是“文字输入意图”,但输入法上屏前它只收到拼音字母,不是最终汉字——所以不能靠它过滤中文数字 - 真正可靠的 WPF 方案是绑定
TextBox.Text到 ViewModel 的string属性,用INotifyPropertyChanged+ 正则清洗,再配合UpdateSourceTrigger=PropertyChanged - 别试图在 WPF 里模仿 WinForms 的
e.Handled = true写法,PreviewTextInput的e.Handled = true只禁文字,不影响Delete或Backspace,还得额外监听PreviewKeyDown










