C# TextBox中只允许输入数字的解决方法

   最近看到一些关于TextBox中限制只允许输入数字的博文,这类问题常常用事后处理模式:录入字符结束后在控件离开(如Exit事件)或确认时进行判 断。本文探讨控件录入操作的事前处理模式:做录入操作时屏蔽非数字字符。下面,结合笔者前段时间修改完善的开源数值文框TNumEditBox控件,介绍 一个基于定制TextBox控件的解决方法。 


在定制的TextBox控件中,如果只允许输入数字,需要考虑如下三种情况: 
1).正常按键输入的字符,包括西文、中文字符等 
2).通过键盘快捷键方式贴入的文本,即Ctrl+V操作 
3).通过上下文关联菜单的Mouse操作贴入的文本,即”粘贴“操作 
在探讨的同类文章中,多数只考虑了第1种情况,忽略得了第2、3种常见的操作。本文探讨的处理方法核心思路是重写事件OnKeyPress()和两个方法 ProcessCmdKey()与WndProc(),并把Ctrl+V、关联菜单的Paste操作统一到键盘录入操作中,从而在 OnKeyPress()屏蔽掉非数字键。 

1、重写键盘事件OnKeyPress()  
键盘输入的字符可以通过重写TextBox控件的OnKeyPress()事件处理,见如下代码:

        protected override void OnKeyPress(KeyPressEventArgs e) // 屏蔽非数字键

        {

                 base.OnKeyPress(e);

                 if (this.ReadOnly) // 只读, 不处理

                         return;

                if ((int)e.KeyChar <= 32) // 特殊键(含空格), 不处理 

                         return;

                if (!char.IsDigit(e.KeyChar)) // 非数字键, 放弃该输入

                {

                         e.Handled = true;

                        return;

                }

        }


2、重写命令键处理方法ProcessCmdKey()  
可以在ProcessCmdKey()中捕获快捷键Ctrl+V操作。首先要清除当前的选择文本,然后读取剪切板ClipBoard中的内容,最后通过模 拟键盘输入的方式”输入“ClipBoard的内容。需要指出,在ProcessCmdKey()方法中不能使用静态方法 SendKeys.Send(),但可以通过控件的WndProc()方法发送字符消息以达到模拟键盘录入的目的。见如下代码: 
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // 捕获Ctrl+V

        {

                 if (keyData == (Keys)Shortcut.CtrlV) // 快捷键 Ctrl+V 粘贴操作

                {

                         this.ClearSelection();

                         string text = Clipboard.GetText();

                          for (int k = 0; k < text.Length; k++) // can not use SendKeys.Send

                         { // 通过消息模拟键盘输入, SendKeys.Send()静态方法不行

                                 SendCharKey(text[k]);

                          }

                        return true;

                }

                 return base.ProcessCmdKey(ref msg, keyData);

        }

 

        private void SendCharKey(char c) // 通过消息模拟键盘录入

        {

                Message msg = new Message();

                msg.HWnd = this.Handle;

                msg.Msg = WM_CHAR; // 输入键盘字符消息

                msg.WParam = (IntPtr)c;

                 msg.LParam = IntPtr.Zero;

                base.WndProc(ref msg);

        }


3、重写消息处理方法WndProc()  
可以在定制TextBox控件中创建无内容的上下文菜单对象,从而屏蔽该菜单,方法是在定制控件的构造函数中增加如下代码: 
public class CustomTextBox : TextBox

        { // 创建无内容菜单对象, 等价屏蔽该控件的上下文菜单

                this.ContextMenu = new ConTextMenu();

        }

        由于上下文菜单的Paste操作对应Windows的WM_PASTE消息,于是可以在控件的WndProc()方法中捕获该消息,然后获得剪切板 ClipBoard中的内容,最后通过SendKeys.Send()方法模拟键盘录入操作。需要注意,这里不能调用前面ProcessCmdKey() 中模拟键盘输入函数SendCharKey()。见如下代码: 
protected override void WndProc(ref Message m) // 捕获Mouse的Paste消息

        {

                if (m.Msg == WM_PASTE) // 选择上下文菜单的"粘贴"操作

                {

                         this.ClearSelection();

                        SendKeys.Send(Clipboard.GetText()); // 模拟键盘输入

                }

                else

                 {

                         base.WndProc(ref m);

                }

        }


4、消除选择ClearSelection()、删除字符DeleteText() 
        还必须分析前面代码中的两个函数: 
ClearSelection()用以清除当前的选择文本,即清除this.SelectedText 
DeleteText()则删除当前字符 
需要指出其中的技巧,就是转换Delete键操作为BackSpace操作。此外,函数DeleteText()还需要确定当前的this.SelectionStart值。具体代码如下: 
private void ClearSelection() // 清除当前TextBox的选择

        {

                 if (this.SelectionLength == 0)

                         return;

                 int selLength = this.SelectedText.Length;

                 this.SelectionStart += this.SelectedText.Length; // 光标在选择之后

                 this.SelectionLength = 0;

                 for (int k = 1; k <= selLength; k++)

                         this.DeleteText(Keys.Back);

        }

 

        private void DeleteText(Keys key) // 删除字符并计算SelectionStart值

        {

                  int selStart = this.SelectionStart;

                 if (key == Keys.Delete) // 转换Delete操作为BackSpace操作

                 {

                         selStart += 1;

                         if (selStart > base.Text.Length)

                                  return;

                 }

                 if (selStart == 0 || selStart > base.Text.Length) // 不需要删除

                         return; 

                  if (selStart == 1 && base.Text.Length == 1)

                 {

                         base.Text = "";

                         base.SelectionStart = 0;

                 }

                 else // selStart > 0

                 {

                          base.Text = base.Text.Substring(0, selStart - 1) + base.Text.Substring(selStart, base.Text.Length - selStart);

                         base.SelectionStart = selStart - 1;

                 }

        }


5、结语  
本文探讨的是TextBox控件输入的事前处理模式,即在输入字符的同时屏蔽非数字键。在实际应用中一般采取事后处理模式,即在TextBox控件的 Exit、Validate等事件中进行输入后处理——离开该控时进行验证。但事后处理模式有如下不足: 
与数据源绑定时输入非数字字符可能抛出异常,需要考虑异常捕获 
需要判断数据并给出错误提示等处理 

上述内容是从笔者的开源数值型数据编辑控件TNumEditBox中修改删减而来的,该控件考虑的情况比只允许数字输入要复杂得多,感兴趣者可以参考并指 正。需要指出,TNumEditBox的核心思路来自免费的Delphi控件PBNumEdit和开源的C#控件BANumEdit。作为回报,笔者也将 TNumEditBox开源并发布到CodeProject。
这里探讨的是屏蔽非数字键输入,显然可以推广到屏蔽其它特殊键如Tab和指定字母等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值