王彦为

聚沙成塔
  1. 首页
  2. WPF
  3. 正文

WPF的TextBox输入验证之ValidationRule验证

2016-12-22 63393点热度 85人点赞 0条评论

接上一篇文章《WPF的TextBox输入验证之Exception验证》,该文章继续讲述TextBox输入验证的方法,利用ValidationRule验证。

效果



初步方案

// 第一步,修改TextBox的Validation.ErrorTemplate
// 修改方法参考文章《WPF的TextBox输入验证之Exception验证》或下载源码

// 第二步,写验证规则
using System.Windows.Controls;
class AgeRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        int age;
        if (!int.TryParse(value.ToString(), out age))
        {
            return new ValidationResult(false, "Invalid number format");
        }
        if (age > 150 || age < 0)
        {
            return new ValidationResult(false, "Age should between 0 and 150");
        }
        return ValidationResult.ValidResult;
    }
}
// 第三步,写XAML布局
<TextBox Grid.Row="1" Grid.Column="1" Name="txtAge" >
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" >
            <Binding.ValidationRules>
                <local:NumberRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

// 第四步,提交时验证所有控件是否满足要求
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
    if (!Validation.GetHasError(txtName) && !Validation.GetHasError(txtAge))
    {
        MessageBox.Show("Verificate successfully.");
    }
    else
    {
        MessageBox.Show("Please input correct data in red textbox","Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
    }
}

该方案有两个的缺点:一、提交表单时需要验证所有控件是否满足要求,所以所有TextBox都需要命名;二、每个属性都需要写一个验证类,工作量较大。针对第一点我们查找出页面中所有的TextBox控件,然后进行遍历判断,代码如下:

private void Submit()
{
    List<TextBox> texboxs = new List<TextBox>();
    GetChildrenObject(this, ref texboxs, true);
    foreach (var texbox in texboxs)
    {
        if (Validation.GetHasError(texbox))
        {
            MessageBox.Show("Please input correct data in red textbox", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            return;
        }
    }
    MessageBox.Show("Verificate successfully.");
}
private void GetChildrenObject<T>(DependencyObject obj, ref List<T> list, bool isDeepSearch) where T : FrameworkElement
{
    DependencyObject child = null;
    for (var i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
    {
        child = VisualTreeHelper.GetChild(obj, i);

        if (child is T)
        {
            list.Add((T)child);
        }
        else
        {
            if (isDeepSearch)
            {
                GetChildrenObject(child, ref list, true);
            }
        }
    }
}

针对第二点,我们可以抽象出一个通用的验证类,例如年龄的范围是0-150岁,身高的的范围是40-300cm,那么我们抽象出一个数据范围验证类,在Xaml中设置最大值和最小值,改进方案如下。

改进方案

<TextBox Grid.Row="1" Grid.Column="1" Name="txtAge" >
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" >
            <Binding.ValidationRules>
                <local:NumberRule Minimum="0" Maximum="150"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>
<TextBox Grid.Row="1" Grid.Column="1" Name="txtHeight" >
    <TextBox.Text>
        <Binding Path="Height" UpdateSourceTrigger="PropertyChanged" >
            <Binding.ValidationRules>
                <local:NumberRule Minimum="40" Maximum="300" ErrorMessage="身高范围[40,300]cm"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

// 数字验证类
class NumberRule : ValidationRule
{
    // 添加ErrorMessage字段,用于自定义错误提示
    public string ErrorMessage { get; set; }
    public double Minimum { get; set; }
    public double Maximum { get; set; }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        double number;
        if (!double.TryParse(value.ToString(), out number))
        {
            return new ValidationResult(false, "Invalid number format");
        }
        if (number > Maximum || number < Minimum)
        {
            if(!string.IsNullOrEmpty(ErrorMessage))
            {
                return new ValidationResult(false, ErrorMessage);
            }
            else
            {
                return new ValidationResult(false, string.Format("Value should between {0} and {1}", Minimum, Maximum));
            }
           
        }
        return ValidationResult.ValidResult;
    }
}

完美主义者

经过改进后的方案可以说是相当完美了,但是还是发现几个奇怪的现象:
1、TextBox代码比较臃肿,每个TextBox至少需要9行代码,而且还无法使用模板解决
2、属性的范围及错误提示都在xaml中
3、Submit时,是对Texbox进行验证,而非属性本身

针对第一点了其实还能接受,至于第二点,如果数据的验证范规则或者范围改变,需要修改前端代码,更多人倾向于在后端写验证规则,前端调用。所以有没有一种方式是后端验证,将验证的结果通知到UI呢?这个就是我们下一篇文章要介绍的。《WPF的TextBox输入验证之IDataErrorInfo验证》。

源码下载

立即下载
标签: 暂无
最后更新:2020-09-27

王彦为

新生代农民工,十年医疗器械行业从业经验,现居苏州。爱生活,爱做梦。

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2022 王彦为. ALL RIGHTS RESERVED.

苏ICP备16063331号-1

苏公网安备32050702011313号