C#旨在设计成为一种「简单、现代、通用」,以及面向对象的程序设计语言。其中c# textbox数字输入需要注意的一些情况容易被忽略,针对这一情况,笔者将在这篇文章中分享自己的一些经验。
最近看到一些关于c# textbox数字中限制只允许输入数字的博文,这类问题常常用事后处理模式:录入字符结束后在控件离开(如Exit事件)或确认时进行判断。本文探讨控件录入操作的事前处理模式:做录入操作时屏蔽非数字字符。下面,结合笔者前段时间修改完善的开源数值文框TNumEditBox控件,介绍一个基于定制c# textbox数字控件的解决方法。
在定制的c# textbox数字控件中,如果只允许输入数字,需要考虑如下三种情况:
正常按键输入的字符,包括西文、中文字符等
通过键盘快捷键方式贴入的文本,即Ctrl+V操作
通过上下文关联菜单的Mouse操作贴入的文本,即”粘贴“操作 在探讨的同类文章中,多数只考虑了第1种情况,忽略得了第2、3种常见的操作。本文探讨的处理方法核心思路是重写事件OnKeyPress()和两个方法 ProcessCmdKey()与WndProc(),并把Ctrl+V、关联菜单的Paste操作统一到键盘录入操作中,从而在 OnKeyPress()屏蔽掉非数字键。
1、重写键盘事件OnKeyPress()
键盘输入的字符可以通过重写c# 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)
- {
-
if (keyData == (Keys)Shortcut.CtrlV)
- {
-
this.ClearSelection();
-
string text = Clipboard.GetText();
-
for (int k = 0; k < text.Length; k++)
- {
-
- 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()
可以在定制c# 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)
- {
-
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()
- {
-
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)
- {
-
int selStart = this.SelectionStart;
-
if (key == Keys.Delete)
- {
- 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
- {
-
base.Text = base.Text.Substring(0, selStart - 1) +
-
base.Text.Substring(selStart, base.Text.Length - selStart);
-
base.SelectionStart = selStart - 1;
- }
- }
5、结语
本文探讨的是c# textbox数字控件输入的事前处理模式,即在输入字符的同时屏蔽非数字键。在实际应用中一般采取事后处理模式,即在c# textbox数字控件的Exit、Validate等事件中进行输入后处理——离开该控时进行验证。但事后处理模式有如下不足:
与数据源绑定时输入非数字字符可能抛出异常,需要考虑异常捕获
需要判断数据并给出错误提示等处理
上述内容是从笔者的开源数值型数据编辑控件TNumEditBox中修改删减而来的,该控件考虑的情况比只允许数字输入要复杂得多,感兴趣者可以参考并指正。需要指出,TNumEditBox的核心思路来自免费的Delphi控件PBNumEdit和开源的C#控件BANumEdit。作为回报,笔者也将TNumEditBox开源并发布到CodeProject。
----------------------------------------------------------------------------------------------------------------链接地址http://www.csharpwin.com/csharpspace/3990r5799.shtml
|
请发表评论