C#中只接受数字输入的控件

C#中只接受数字输入的控件

关键字: numeric textbox
在MFC里需要获取文本输入时,经常会用到 CEdit或者它的子类。可以通过设置它的 Edit Control Styles来控制Edit控件的一些行为,例如说设置 ES_NUMBER标识使控件只允许接受数字(虽然可以复制-粘贴非数字字符串到这个控件中)。 

在.NET中,用于获取文本输入的控件是 TextBox,但TextBox本身并不包含可以直接调用的方法或属性来将其设置为只接受数字输入。这个问题有好几种方法来解决: 
  • 继承TextBox并覆盖其CreateParams属性,对该属性的Style成员添加ES_NUMBER标识;
  • 这个方法与MFC中用Edit Control Styles来初始化CEdit一样。可以说是最偷懒的方法。
  • 自行监听TextBox的KeyDown事件,实现输入验证(但不保证复制-粘贴输入的正确性);
  • 其实设置 ES_NUMBER做的也是这件事,如果要实现的功能与Windows控件中默认的一样的话没必要自己监听KeyDown事件;如果需要些额外的功能,例如说允许输入负数、十六进制数等默认没有的功能时,则监听KeyDown事件是个有效的方式。
  • 使用第三方编写的继承自TextBox的控件;
  • 这是拥有“不重复发明轮子”精神的人们的做法。既然获取数字输入应该是个常见问题,之前也肯定有人解决过,那么利用别人的解决方案就行。 
    光是 CodeProject上就有好几个与这个相关的实现: 
    Validating Edit Controls。包括了NumericTextBox、AlphanumericTextBox、DateTextBox等许多版本的TextBox子类。值得一看。 
    A numeric textbox with a twist。 
    Numeric TextBox : Allow your users to enter numeric data the easy way
  • 使用MaskedTextBox 控件;
  • 这是.NET Framework自带的一个TextBox的子类,实现了一个带过滤功能的TextBox,可以自定义接受的输入内容的格式。只要设置其 string Mask属性即可。如果觉得 ES_NUMBER的功能不够用,而自行监听KeyDown事件来做验证不够优雅的话,这个MaskedTextBox绝对是值得考虑的选择。例如说,要接受0到999999的数字,只要把Mask属性设为 "999,999.00"就行(意味着六位的可选十进制数字,一个小数点,和两位必须输入的小数)。 MSDN上对这个控件有个简单的 walkthrough
  • 使用NumericUpDown控件。
  •   当需要获取简单数字输入时,在.NET世界中最直接的方法不是去想办法与TextBox搏斗,而应该换个控件来用——NumericUpDown。这个控件不但能接受来自键盘的数字输入,还有一组上下箭头来步进。它包含了许多可以设置的属性,例如显示分隔符逗号的 boolThousandsSeparator、控制最小/最大值的 decimal Minimum/ decimal Maximum属性等。 


下面对这几种解决方法的其中一些稍微讨论一下。 

========================================================================================= 

一、继承TextBox并覆盖其CreateParams属性 

使用这种方法的NumericTextBox的实现(代码的第1-12行)及用例: 
C#代码 
  1. public class NumericTextBox : System.Windows.Forms.TextBox  
  2. {  
  3.     private const int ES_NUMBER = 0x2000; // ( defined in WinUser.h )  
  4.       
  5.     protected override System.Windows.Forms.CreateParams CreateParams {  
  6.         get {  
  7.             System.Windows.Forms.CreateParams cp = base.CreateParams;              
  8.             cp.Style |= ES_NUMBER;  
  9.             return cp;  
  10.         }  
  11.     }  
  12. }  
  13.  
  14. #region use case code sample  
  15.   
  16. sealed class TestForm : System.Windows.Forms.Form  
  17. {  
  18.     private NumericTextBox m_ntxt;  
  19.       
  20.     public TestForm() {  
  21.         InitializeComponent();  
  22.     }  
  23.       
  24.     private void InitializeComponent() {  
  25.         this.m_ntxt = new NumericTextBox();  
  26.         this.m_ntxt.Dock = System.Windows.Forms.DockStyle.Fill;  
  27.           
  28.         this.ClientSize = new System.Drawing.Size(100, 60);  
  29.         this.Controls.Add(this.m_ntxt);  
  30.         this.PerformLayout();  
  31.     }  
  32.       
  33.     [System.STAThread]  
  34.     static void Main(string[] args) {  
  35.         System.Windows.Forms.Application.EnableVisualStyles();  
  36.         System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);  
  37.         System.Windows.Forms.Application.Run(new TestForm());  
  38.     }  
  39. }  
  40.  
  41. #endregion  


运行程序,在输入任意非0-9的字符时的样子: 
 
(截图反映的是在我的简体中文Windows XP上的运行效果;若系统语言不是简体中文的话会根据系统语言而不同) 

如果这个文本框已经能满足需求,就没必要自己监听KeyDown事件那么麻烦了。 

========================================================================================= 

二、自行监听KeyDown事件 

可以参考CodeProject上 Numeric TextBox : Allow your users to enter numeric data the easy way的实现方式。基本原理就是在KeyDown的响应方法中对e.KeyCode进行判断,如果输入不满足条件则设置某个标识,然后再KeyPress的响应方法里设置e.Handled = true;来取消该次事件。 

最简单来说类似这样: 
C#代码 
  1. using System;  
  2. using System.Drawing;  
  3. using System.Windows.Forms;  
  4.   
  5. sealed class TestForm : Form  
  6. {  
  7.     private TextBox m_textBox;  
  8.     private bool m_nonNumberEntered = false;  
  9.       
  10.     public TestForm() {  
  11.         InitializeComponent();  
  12.     }  
  13.       
  14.     private void InitializeComponent() {  
  15.         this.m_textBox = new TextBox();  
  16.         this.m_textBox.Dock = DockStyle.Fill;  
  17.         this.m_textBox.KeyDown += m_textBox_KeyDown;  
  18.         this.m_textBox.KeyPress += m_textBox_KeyPress;  
  19.           
  20.         this.ClientSize = new Size(100, 60);  
  21.         this.Controls.Add(this.m_textBox);  
  22.         this.PerformLayout();  
  23.     }  
  24.       
  25.     private void m_textBox_KeyDown(object sender, KeyEventArgs e) {  
  26.         // Initialize the flag to false.  
  27.         m_nonNumberEntered = false;  
  28.       
  29.         // Determine whether the keystroke is a number from the top of the keyboard.  
  30.         if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9) {  
  31.             // Determine whether the keystroke is a number from the keypad.  
  32.             if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9) {  
  33.                 // Determine whether the keystroke is a backspace.  
  34.                 if(e.KeyCode != Keys.Back) {  
  35.                     // A non-numerical keystroke was pressed.  
  36.                     // Set the flag to true and evaluate in KeyPress event.  
  37.                     m_nonNumberEntered = true;  
  38.                 }  
  39.             }  
  40.         }  
  41.     }  
  42.       
  43.     private void m_textBox_KeyPress(object sender, KeyPressEventArgs e) {  
  44.         // Check for the flag being set in the KeyDown event.  
  45.         if (m_nonNumberEntered) {  
  46.             // Stop the character from being entered into the control  
  47.             // since it is non-numerical.  
  48.             e.Handled = true;  
  49.         }  
  50.     }  
  51.       
  52.     [STAThread]  
  53.     static void Main(string[] args) {  
  54.         Application.EnableVisualStyles();  
  55.         Application.SetCompatibleTextRenderingDefault(false);  
  56.         Application.Run(new TestForm());  
  57.     }  
  58. }  

(判断逻辑来自 KeyEventArgs在MSDN文档上的 范例代码) 

得到的文本框外观与一般的TextBox没区别,只是无法由键盘输入数字字符以外的字符。要避免任意字符串被复制-粘贴进来的话,要另外做些判断。这里就不详细写了。 

========================================================================================= 

三、使用MaskedTextBox 

使用例子: 
C#代码 
  1. using System;  
  2. using System.Windows.Forms;  
  3.   
  4. sealed class TestForm : Form  
  5. {  
  6.     private MaskedTextBox m_maskedTextBox;  
  7.     private ToolTip m_toolTip;  
  8.       
  9.     public TestForm() {  
  10.         InitializeComponent();  
  11.     }  
  12.       
  13.     private void InitializeComponent() {  
  14.         this.m_maskedTextBox = new MaskedTextBox();  
  15.         this.m_maskedTextBox.Mask = "999,999.00";  
  16.         this.m_maskedTextBox.Dock = DockStyle.Fill;  
  17.         this.m_maskedTextBox.MaskInputRejected += m_maskedTextBox_InputRejected;  
  18.         this.m_maskedTextBox.KeyDown += m_maskedTextBox_KeyDown;  
  19.           
  20.         this.m_toolTip = new ToolTip();  
  21.           
  22.         this.ClientSize = new Size(100, 60);  
  23.         this.Controls.Add(this.m_maskedTextBox);  
  24.         this.PerformLayout();  
  25.     }  
  26.       
  27.     private void m_maskedTextBox_InputRejected(object sender,  
  28.         MaskInputRejectedEventArgs e) {  
  29.         toolTip.ToolTipTitle = "Invalid Input";  
  30.         toolTip.Show("Only digits (0-9) are allowed.",  
  31.             m_maskedTextBox, m_maskedTextBox.Location, 5000);  
  32.     }  
  33.       
  34.     private void m_maskedTextBox_KeyDown(object sender, KeyEventArgs e) {  
  35.         m_toolTip.Hide(maskedTextBox);  
  36.     }  
  37.       
  38.     [STAThread]  
  39.     static void Main(string[] args) {  
  40.         Application.EnableVisualStyles();  
  41.         Application.SetCompatibleTextRenderingDefault(false);  
  42.         Application.Run(new TestForm());  
  43.     }  
  44. }  

这段代码是手写的;要是用VS2005/VS2008的设计器的话,这个例子的所有功能都能直接在设计器里指定。 

输入内容(可以看到分隔符都不需要自己写了,已经写好在输入框里;只要填空就行): 
 
输入内容不符合Mask属性指定的模式时: 
 

========================================================================================= 

四、使用NumericUpDown 

C#代码 
  1. using System;  
  2. using System.Drawing;  
  3. using System.Windows.Forms;  
  4.   
  5. sealed class TestForm : Form  
  6. {  
  7.     private NumericUpDown m_numericUpDown;  
  8.       
  9.     public TestForm() {  
  10.         InitializeComponent();  
  11.     }  
  12.       
  13.     private void InitializeComponent() {  
  14.         this.m_numericUpDown = new NumericUpDown();  
  15.         this.m_numericUpDown.Value = 100;  
  16.         this.m_numericUpDown.Dock = DockStyle.Fill;  
  17.         this.m_numericUpDown.ThousandsSeparator = true;  
  18.         this.m_numericUpDown.Maximum = int.MaxValue;  
  19.           
  20.         this.ClientSize = new Size(100, 60);  
  21.         this.Controls.Add(this.m_numericUpDown);  
  22.         this.PerformLayout();  
  23.     }  
  24.       
  25.     [System.STAThread]  
  26.     static void Main(string[] args) {  
  27.         Application.EnableVisualStyles();  
  28.         Application.SetCompatibleTextRenderingDefault(false);  
  29.         Application.Run(new TestForm());  
  30.     }  
  31. }  

这段代码是手写的;要是用VS2005/VS2008的设计器的话,这个例子的所有功能都能直接在设计器里指定。 
NumericUpDown的内容的值可以用Value属性来设置或获取,类型为 decimal。 

截图:(输入不符合要求的字符时,默认行为是beep一下,没有工具条的提示) 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值