自定义WPF常用控件(2)--输入过滤
有时候,我们需要对用户输入的信息进行处理,当用户输入了违规格式的的数据时,我们需要在后台判断,并且给出提示,但是这样一来是加重了后台的负担(尤其是B/S架构的系统或者是基于WCF服务的系统),而且一旦要对所有输入进行控制时,修改的工作量就会很大,所以我们希望能在前台进行过滤,如同ASP.NET的Ajax验证控件一样。
为了解决这个问题,我这里采用了重载输入控件和自定义控件结合的方式。
输入类的控件主要是TextBox,RichTextBox和PasswordBox,其中TextBox跟RichTextBox的改造完全一样,因为他们可以继承,所以采用继承的方式来设计两个控件,而PasswordBox不能继承,就只能用UserControl来实现。
一、 ValidTextBox、ValidRichTextBox
两者实现方法一样,这里就介绍下TextBox,首先添加用户控件,如下图
添加用户控件
添加之后,在Xmal文件中,将根节点改为由UserControl改为TextBox,如下图
改变根节点
再在后台代码文件(. CS)文件中将继承的类改为TextBox,如下图
修改继承
然后实现控件的事件PreviewTextInput:
/// <summary>
/// 输入改变时,验证输入
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
bool match = System.Text.RegularExpressions.Regex.IsMatch(e.Text, m_RegexExpression);
e.Handled = m_IsMatchedValid ? !match : match;
base.OnPreviewTextInput(e);
}
事件处理中,把e.Handled设置为True,则表示事件已经处理过,调用base.OnPreviewTextInput(e);之后事件TextInput事件会触发,此时不再处理输入事件,则用户的输入不会被处理,表现在界面上就不会有任何反应,当然也可以对此事件进行丰富,我这里只是提供一个模板。如果要丰富此事件,想要在用户输入了非法字符时进行提示,则可以如此修改:
bool match = System.Text.RegularExpressions.Regex.IsMatch(e.Text, m_RegexExpression);
e.Handled = m_IsMatchedValid ? !match : match;
if(e. Handled)
//做点什么…
base.OnPreviewTextInput(e);
其中有两个变量,m_RegexExpression是控件需要匹配的正则表达式,默认是匹配单引号,因为很多MIS系统不能输入单引号;m_IsMatchedValid是当如果控件输入的字符匹配了正则表达式时,判定输入到底是合法还是不合法,这个变量主要用在对控件输入做匹配过滤和匹配放行时的判断,默认为false,即若匹配则不合法,需过滤。
二、 ValidPasswordBox
同TextBox一样,添加用户控件,但是不再修改根节点和集成的父类(因为PasswordBox是Sealed密封类,想继承都继承不了),此时在用户控件中拖入一个PasswordBox
使用用户控件
之后,添加变量m_RegexExpression、m_IsMatchedValid以及它们的对应公有属性,再实现PreviewTextInput事件,内容跟ValidTextBox完全一样。
现在讲讲ValidPassword不同的地方,由于此控件不是继承自PasswordBox,而是UserControl,所以只有UserControl的属性,如果想像PasswordBox控件一样使用其属性(比如PasswordBox有个string类型的属性Password,但是Usercontrol没有),尤其是项目已经完成了很多,在代码里都是直接使用的PasswordBox的属性,现在又想批量的改成使用ValidPasswordBox时,可能会出现部分属性提示不存在的情况,要解决这类情况,最好是在ValidPasswordBox里面建一个同名属性。举例如下:
/// <summary>
/// 获取或设置密码
/// </summary>
public string Password
{
get { return passwordBox.Password; }
set { passwordBox.Password = value; }
}
其实这个属性设置和返回的还是PasswordBox的,但整个项目中用到PasswordBox的地方,就不需要修改,只需要修改Xmal文件中的节点名称就行了。
我目前设置了Password和MaxLength属性,大家在使用中可以自行丰富。
然后是样式的设置,将项目中的PasswordBox改成ValidPasswordBox之后,由于控件实质上改为了Usercontrol,所以Style也是给UserControl设置的,效果往往与之前的不同,所以要写一个样式,对应着内置的PasswordBox控件的Style。
#region 提示字体样式依赖属性
/// <summary>
/// 提示字体样式依赖属性
/// </summary>
static readonly DependencyProperty PasswordBoxStyleProperty =
DependencyProperty.Register(
"PasswordBoxStyle",
typeof(Style),
typeof(ValidPasswordBox),
new FrameworkPropertyMetadata(new PropertyChangedCallback(PasswordBoxStyleChangedCallback)));
/// <summary>
/// 获取或设置提示字体样式
/// </summary>
[Category("样式"), Description("提示字体样式")]
public Style PasswordBoxStyle
{
get { return (Style)GetValue(PasswordBoxStyleProperty); }
set { SetValue(PasswordBoxStyleProperty, value); }
}
/// <summary>
/// 提示字体样式样式改变回调
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void PasswordBoxStyleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ValidPasswordBox control = ((ValidPasswordBox)d);
control.passwordBox.Style = control.PasswordBoxStyle;
}
#endregion
(关于样式属性的实现,相关说明请参见自定义WPF常用控件(1)--页码控件-四、控件样式)
完整源代码下载:/Files/chenl861004/WPF控件/ValidControl.rar