自认为注释比较详细了,所以就不作介绍了. 我也没有搜索其他类似的控件来进行比较,可能其他控件更好,仅作一起学习吧。
如有错误或其他更好的控件,请留言。
using System; using System.Drawing; using System.Windows.Forms;
namespace MyLibrary.Controls { /// <summary> /// 一个只允许输入数字值的文本框,并且带有输入范围设置功能。 /// </summary> public class NumericTextBox : System.Windows.Forms.TextBox { [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool MessageBeep(uint beep);
private int minimum = 0; private int maximum = 100; private bool useRange = false; private string lastChar; public NumericTextBox() { base.Text = "0"; }
/// <summary> /// 获取或设置可以接受的数据集范围 /// 如果设置的最大值大于等于设置的最小值, /// 则表示允许的值在这两个设置值之间。 /// 如果设置的最大值小于设置的最小值, /// 则表示允许的值在这两个设置值之外。 /// </summary> public Size SetRange { get { return new Size(minimum, maximum); } set { if (this.SetRange == value) return;
minimum = value.Width; maximum = value.Height; // 空文本的数值范围验证 if (this.useRange && base.Text == "") { base.Text = GetMinimumText(); return; }
this.ValidateText(); } }
// 以下两个辅助方法是 VS.NET 设计器所需的。 public bool ShouldSerializeSetRange(){ return (new Size(0, 100) != this.SetRange); } public void ResetSetRange() { this.maximum = 100; this.minimum = 0; }
/// <summary> /// 获取或设置是否要使用限定值的范围 /// </summary> [System.ComponentModel.DefaultValue(false)] public bool UseRange { get { return this.useRange; } set { if (this.useRange == value) return; this.useRange = value;
// 空文本的数值范围验证 if (this.useRange && base.Text == "") { base.Text = GetMinimumText(); return; } this.ValidateText(); } }
/// <summary> /// 为了检查程序设置的文本值有效性,所以隐藏了基类的 Text 属性。 /// </summary> [System.ComponentModel.DefaultValue("0")] public new string Text { get { return base.Text; } set { // 检查是否是一个数字 try { Double.Parse(value); } catch { // 空文本的数值范围验证 if (this.useRange && base.Text == "") { base.Text = GetMinimumText(); } return; } base.Text = value; this.ValidateText(); } }
/// <summary> /// 复盖基类的 OnKeyPress 方法 /// 用以检测按键是否符合要求。 /// </summary> /// <param name="e"></param> protected override void OnKeyPress(KeyPressEventArgs e) { // 回车符,检查文本数字值的有效性 if (e.KeyChar == 13) { this.ValidateText(); // 注意,此处要先检查后再调用基类方法 // 因为基类方法引发的事件处理回调中需要使用到控件的值。 // 为了回调能够得到准确的值,所以要先进行检查处理。 base.OnKeyPress(e); return; }
// 调用基类方法。先由基类来处理此次按键事件。 base.OnKeyPress(e); // 如果基类的调用已处理了此键,直接返回吧。 if (e.Handled) return;
// 如果是 - 或 +,只能在第一个位置输入,且不能重复输入。 if ( e.KeyChar == '-' || e.KeyChar == '+') { if (base.Text.StartsWith("-") || base.Text.StartsWith("+") || base.SelectionStart != 0) // 检测光标是否在第一个位置上 e.Handled = true; } else if ( e.KeyChar == '.' ) // 小数点最多只能输入一个。 { e.Handled = (base.Text.IndexOf('.') >= 0); } else { // 其他情况只能是数字字符和后退符。 // 可自行修改补充,以适合更广泛的要求。 e.Handled = !(Char.IsDigit(e.KeyChar) || e.KeyChar == 8); } // 如果是不合要求的字符,则发出一个警告音。 if (e.Handled) MessageBeep(0x00000030); }
/// <summary> /// 复盖基类的 OnValidated 方法 /// 用以检测文本是否符合范围要求。 /// </summary> /// <param name="e"></param> protected override void OnValidated(EventArgs e) { base.OnValidated(e); this.ValidateText(); }
/// <summary> /// 当非空文本时,验证文本的数值范围。 /// </summary> protected virtual void ValidateText() { // 如果没有使用范围验证,直接返回 if (this.useRange == false) return;
// 如果文本为空、-、+,不在此作任何验证。 if (this.IsEmpty()) return;
decimal val = 0; bool normal = true; try { val = Convert.ToDecimal(base.Text); } catch { normal = false; }
// 如果解析正常 if (normal) { // 如果设置的最大值大于等于设置的最小值, // 则表示允许的值在这两个设置值之间。 if (maximum >= minimum) { if ( val > maximum ) { base.Text = maximum.ToString(); } else if ( val < minimum ) { base.Text = minimum.ToString(); } } // 如果设置的最大值小于设置的最小值, // 则表示允许的值在这两个设置值之外。 else { if ( val < minimum && val > maximum ) { base.Text = maximum.ToString(); // 也可使用以下方法,结果相同。 // base.Text = GetMinimumText(); } } } else { // 如有异常,则使用设置的最小值。 base.Text = GetMinimumText(); }
// 如果除了 - 和 + 以外的文本长度为 1,记住它。 // 因为用户可能会在删除了最后一个字符后,将输入焦点转移到其他控件。 // 这么做是为了能在失去焦点时保持文本框不为空。 // 有关操作,请见 OnLostFocus。 if ( base.Text.StartsWith( "-" ) || base.Text.StartsWith( "+" )) { if ( base.Text.Length == 2) { lastChar = base.Text; } } else { if ( base.Text.Length == 1) { lastChar = base.Text; } } }
protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e);
// 当用户的输入焦点离开了此文本框时, // 并且当设定了数值的范围,并且文本的宽度为 0 时, // 将以前记住的最后有效字符串重新填充。 // 因为设置了范围后,就不能让文本框中为空。 if ( this.IsEmpty() && useRange ) { if (lastChar != null) base.Text = lastChar; else base.Text = GetMinimumText(); } } protected string GetMinimumText() { if (maximum >= minimum) { return minimum.ToString(); } else { return maximum.ToString(); } }
protected bool IsEmpty() { return (base.Text == "" || base.Text == "-" || base.Text == "+"); } } }

|