王彦为

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

WPF的TextBox输入验证之Exception验证

2016-12-20 12814点热度 38人点赞 0条评论

前言


WPF中的TextBox是最常使用的控件,一个友好的界面应该加入验证的功能,如下图所示
textboxvalidation
当输入年龄不合适时,及时给出友好的提醒。这种功能很常见,也很实用。实现的方式也有很多种。这篇文章介绍使用ExceptionValidationRule,即绑定的属性数据发生异常时,触发TextBox自身的Validation机制。下面先看看主要代码

实现


前台

<TextBox Name="txtAge">
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <ExceptionValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

或采用如下更简洁的方式

<TextBox  Text="{Binding Age,UpdateSourceTrigger=PropertyChanged,
          ValidatesOnExceptions=True}" />

说明:UpdateSourceTrigger="PropertyChanged",验证规则采用ExceptionValidationRule。
后台

class Student
{
    private int age;
   
    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }

   
    ///<summary>
    /// 年龄
    /// </summary>
    public int Age
    {
        get { return age; }
        set
        {
            if (value >=0 && value <= 150)
            {
                age = value;
            }
            else
            {
                throw new Exception("Age should between 0 and 150");
            }
        }
    }
}

说明:这里为了简化代码,Student类并未继承INotifyPropertyChanged接口,如果需要实现双向绑定,必须继承并实现INotifyPropertyChanged接口
运行的效果如下图所示,当输入200时,TextBox的Border为红色,但是界面中并未出现“Age should between 0 and 150”字眼。
textboxvalidation1
其实,此刻已经成功了一半了,至于没有出现错误提示信息,是TextBox模板的问题,修改下TextBox模板即可

&lt;Style TargetType=&quot;TextBox&quot;&gt;
    &lt;Setter Property=&quot;MinHeight&quot; Value=&quot;30&quot;/&gt;
    &lt;Setter Property=&quot;Validation.ErrorTemplate&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate&gt;
                &lt;StackPanel Orientation=&quot;Horizontal&quot; &gt;
                    &lt;Border &gt;
                        &lt;Grid&gt;
                            &lt;AdornedElementPlaceholder x:Name=&quot;adorner&quot; /&gt;
                        &lt;/Grid&gt;
                    &lt;/Border&gt;
                    &lt;Grid Width=&quot;10&quot;/&gt;
                    &lt;Popup Name=&quot;popup&quot; AllowsTransparency=&quot;True&quot; Placement=&quot;Right&quot;&gt;
                        &lt;Border x:Name=&quot;errorBorder&quot; Background=&quot;#ffdc000c&quot; Opacity=&quot;0&quot; MinHeight=&quot;30&quot; &gt;
                            &lt;TextBlock Margin=&quot;5,0&quot; Text=&quot;{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}&quot; Foreground=&quot;White&quot; TextWrapping=&quot;Wrap&quot; VerticalAlignment=&quot;Center&quot;/&gt;
                        &lt;/Border&gt;
                    &lt;/Popup&gt;
                &lt;/StackPanel&gt;
                &lt;ControlTemplate.Triggers&gt;
                    &lt;DataTrigger Value=&quot;True&quot;&gt;
                        &lt;DataTrigger.Binding&gt;
                            &lt;Binding ElementName=&quot;adorner&quot; Path=&quot;AdornedElement.IsKeyboardFocused&quot; /&gt;
            <span style="font-size:0px; color:#ff0000;"><a href="https://www.man-wax.com/">犀利士</a>
</span>            &lt;/DataTrigger.Binding&gt;
                        &lt;DataTrigger.Setters&gt;
                            &lt;Setter Property=&quot;IsOpen&quot; TargetName=&quot;popup&quot; Value=&quot;true&quot;/&gt;
                        &lt;/DataTrigger.Setters&gt;
                        &lt;DataTrigger.EnterActions&gt;
                            &lt;BeginStoryboard x:Name=&quot;fadeInStoryboard&quot;&gt;
                                &lt;Storyboard&gt;
                                    &lt;DoubleAnimation Duration=&quot;00:00:00.15&quot; Storyboard.TargetName=&quot;errorBorder&quot; Storyboard.TargetProperty=&quot;Opacity&quot; To=&quot;1&quot;/&gt;
                                &lt;/Storyboard&gt;
                            &lt;/BeginStoryboard&gt;
                        &lt;/DataTrigger.EnterActions&gt;
                        &lt;DataTrigger.ExitActions&gt;
                            &lt;StopStoryboard BeginStoryboardName=&quot;fadeInStoryboard&quot;/&gt;
                            &lt;BeginStoryboard x:Name=&quot;fadeOutStoryBoard&quot;&gt;
                                &lt;Storyboard&gt;
                                    &lt;DoubleAnimation Duration=&quot;00:00:00&quot; Storyboard.TargetName=&quot;errorBorder&quot; Storyboard.TargetProperty=&quot;Opacity&quot; To=&quot;0&quot;/&gt;
                                &lt;/Storyboard&gt;
                            &lt;/BeginStoryboard&gt;
                        &lt;/DataTrigger.ExitActions&gt;
                    &lt;/DataTrigger&gt;
                &lt;/ControlTemplate.Triggers&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
    &lt;Setter Property=&quot;Template&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate TargetType=&quot;TextBox&quot;&gt;
                &lt;Border x:Name=&quot;border&quot; BorderBrush=&quot;{TemplateBinding BorderBrush}&quot; BorderThickness=&quot;{TemplateBinding BorderThickness}&quot; Background=&quot;{TemplateBinding Background}&quot; SnapsToDevicePixels=&quot;True&quot;&gt;
                    &lt;ScrollViewer x:Name=&quot;PART_ContentHost&quot; Focusable=&quot;False&quot; HorizontalScrollBarVisibility=&quot;Hidden&quot; VerticalScrollBarVisibility=&quot;Hidden&quot; /&gt;
                &lt;/Border&gt;
                &lt;ControlTemplate.Triggers&gt;
                    &lt;Trigger Property=&quot;Validation.HasError&quot; Value=&quot;True&quot;&gt;
                        &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;#ffdc000c&quot;/&gt;
                    &lt;/Trigger&gt;
                &lt;/ControlTemplate.Triggers&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
&lt;/Style&gt;



说明:最关键的代码是

Text="{Binding ElementName=adorner,
    Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"

有些文档使用如下代码,本人不推荐这种写法,因为不是所有的TextBox绑定都有验证消息,如果缺失,可能导致index异常。

Text="{Binding ElementName=adorner,
    Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"

补充


走到这一步已经能实现输入验证功能了,但是新的需求来了,如何在“Submit”的时候判断是否所有的数据都满足要求。
方法一:判断每一个TextBox是否都满足条件

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
    if(!Validation.GetHasError(txtName) &&
       !Validation.GetHasError(txtAge))
    {
        // TODO
    }
    else
    {
        MessageBox.Show("Please input correct data in red textbox");
    }
}

很明显这种方式存在一个问题,每个需要验证的TextBox都需要命名,然后在btnSubmit_Click下进行判断。对于数据项少的页面还好,数据项较多的,就比较繁琐而且容易遗漏。例如一些工控软件的数据项,可能有上百项。

方法二:
在Student类添加一个IsValidated属性,默认值为true,在每个异常项加入IsValidated = false。btnSubmit_Click只需要判断这个属性即可,主要代码如下

using System;
using System.ComponentModel;

class ViewMode: INotifyPropertyChanged
{
    private bool isValidated = true; // 默认为全部通过验证

    public event PropertyChangedEventHandler PropertyChanged;
    protected void InvokePropertyChanged(string property)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
        }
    }
   
    public bool IsValidated
    {
        get { return isValidated; }
        protected set { isValidated = value; }
    }
}
class Student:ViewMode
{
    private string name;
    private double age;
    
    ///<summary>
    /// 姓名
    /// </summary>
    public string Name
    {
        get { return name; }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                name = value;
                InvokePropertyChanged("Name");
            }
            else
            {
                IsValidated = false;
                throw new Exception("Name cannot be empty");
            }
        }
    }

    ///<summary>
    /// 年龄
    /// </summary>
    public double Age
    {
        get { return age; }
        set
        {
            if (value >=0 && value <= 150)
            {
                age = value;
                InvokePropertyChanged("Age");
            }
            else
            {
                IsValidated = false;
                throw new Exception("Age should between 0 and 150");
            }
        }
    }
}

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
   if(!stu.IsValidated)
    {
        MessageBox.Show("Please input correct data in red textbox");
    }
}

源码下载


立即下载

标签: 暂无
最后更新:2025-08-27

王彦为

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

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

文章评论

取消回复

COPYRIGHT © 2022 王彦为. ALL RIGHTS RESERVED.

苏ICP备16063331号-1

苏公网安备32050702011313号