为了方便讲解之后的内容 这里还是按照[GDI+程序设计]一书上面的内容派生一个控件吧 因为后面的内容会用到这个控件来举例子
还是和[GDI+程序设计]一样派生一个TextBox不过功能就不做书上那么全了 简单演示一下效果就行了 因为主要目的是为了方便后面的内容来举例子 所以就做个简单的 做这样一个效果:
给控件一个[NumberRange]属性 这个属性用来验证用户的输入 如果用户在控件里面输入的是一个在范围内的数字 那么控件不做任何变化 否则背景色变成黄色
首先创建一个控件继承TextBox然后给他一个NumberRange属性 不过注意了 这个属性是字符串类型:
private int m_nHigh = 100; private int m_nLow = 0; private string _NumberRange = "0,100"; [DefaultValue("0,100")] public string NumberRange { get { return _NumberRange; } set { _NumberRange = value; } }就像这样 明显你能感觉到真正要用的是上面的两个数据 或许这里你有些郁闷 直接把上面两个做成属性不就完了 的确可以这样干 但是我这里只想提供一个属性让用户去设置 而不是两个 想一下这种情况又不是没有 比如窗体的Size属性Location属性 是不是也都和我上面的截图那个样子用【数字1,数字2】的形式来赋值 只是Size和Location可以把属性展开就像这样:
至于这个问题 后面的内容再说先一步一步的来 然后后面在做成像上面截图的样子
继续回到代码的问题 就想上面那些写代码还没完 还得把NumberRange和m_nLow和m_nHigh两个数关联起来 要关联其实也是在set里面 当用户给NumberRange设置值的时候实质上是在给m_nLow和m_nHigh赋值 而我们需要在set赋值的时候去完成这个转换:
public string NumberRange { get { return _NumberRange; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("[NumberRange] can not be empty or null!"); string[] v = ((string)value).Split(','); if (v.Length != 2) throw new ArgumentException("Invalid input!"); try { m_nLow = int.Parse(v[0]); m_nHigh = int.Parse(v[1]); } catch (FormatException ex) { throw ex; } _NumberRange = value; } }代码很简单 估计也不用解释了 接下来写个方法来验证用户输入的值是否合法:
private bool CheckRange(string strNum) { if (string.IsNullOrEmpty(strNum)) return false; try { int v = int.Parse(strNum); return v >= m_nLow && v <= m_nHigh; } catch (FormatException) { return false; } }方法接受一个字符串 判断这个字符串是否是合法的 最后剩下的就是去验证用户输入的数据是否合法了
在TextBox控件中提供了两个事件用来验证:
上面一个发生在验证之后 下面一个是验证之时 这个验证什么意思 简单点说 也就是当文本框将要失去焦点的时候 就会触发这个事件 可以在里面写代码验证用户输入的数据是否合法:
protected override void OnValidating(CancelEventArgs e) { this.BackColor = this.CheckRange(this.Text) ? Color.White : Color.Yellow; base.OnValidating(e); }如果合法背景色白色否则黄色 注意这里的事件参数e有一个Cancel属性默认值是false这个属性有啥用?也就是是否取消事件的发生 如果你将这个值设置成true那么文本框将继续持有焦点 如果你把代码改成这样:
protected override void OnValidating(CancelEventArgs e) { this.BackColor = this.CheckRange(this.Text) ? Color.White : Color.Yellow; if (this.BackColor == Color.Yellow) e.Cancel = true; base.OnValidating(e); }
加了一个判断 如果是验证失败的情况下那么Cantel就为true 那么会有啥效果?
我会告诉你我鼠标一直在点窗体的XX么 压根就关不到 为啥?因为Validating之后的所有事件都被取消了 事件顺序是这样的:
Enter - GotFocus - Leave - Validating - Validated - LostFocus也就是说到Validating那里就中断了事件的继续 那么控件也不会失去焦点 所以你其他事情你也干不了 除非通过验证( - -!、、不过对于这种流氓的行为还是不要干的好)
下面是全部代码:
public class NumberTextBox : TextBox { private int m_nHigh = 100; private int m_nLow = 0; private string _NumberRange = "0,100"; [DefaultValue("0,100")] public string NumberRange { get { return _NumberRange; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("[NumberRange] can not be empty or null!"); string[] v = ((string)value).Split(','); if (v.Length != 2) throw new ArgumentException("Invalid input!"); try { m_nLow = int.Parse(v[0]); m_nHigh = int.Parse(v[1]); } catch (FormatException ex) { throw ex; } _NumberRange = value; } } private bool CheckRange(string strNum) { if (string.IsNullOrEmpty(strNum)) return false; try { int v = int.Parse(strNum); return v >= m_nLow && v <= m_nHigh; } catch (FormatException) { return false; } } protected override void OnValidating(CancelEventArgs e) { this.BackColor = this.CheckRange(this.Text) ? Color.White : Color.Yellow; base.OnValidating(e); } }这个代码没什么难度 不过多做解释 派生这个控件主要是为了后面的内容做铺垫 在后面会讲如何想把NumberRange做成像Size那样的 在属性窗口能够展开的 这里只是先做一个初步 后面的话上面的代码还得改 应为要做成像Size那样的 像上面这样是肯定没有办法的、、、