站点图标 江湖人士

JHRS开发框架之WPF数据验证

上一篇文章中说了下团队项目中,一些关于创建目录或者文件的建议,这篇就讨论一下WPF数据验证的话题;无论什么系统,数据验证是一个绕不开的话题,除了在服务器端做验证之外,客户端也是会做同样的事情,只是服务器端可能做得更多而已;那使用WPF开发的系统,是怎样在客户端做数据验证的呢?或者说WPF是怎样在界面上做一些基本的数据合法性校验呢?

这就是本文要探讨的一个话题,如有不对之处,烦请手下留情指证,因为笔者也是现学现卖而折腾出来的这么一个框架,遇到了这个关于数据验证的问题而已。

WPF数据验证

WPF数据验证

这篇文章可能要流产了,原因是在这个演示的框架中,暂时抽不出时间弄一个示例出来,另外笔者也是WPF中的菜鸡,对WPF它的验证机制只是略看过一些博客文章,现就转载一些认为比较不错的文章,但这些文章提到的验证代码并没有上机试过;待闲下来的时候,或许会在演示框架中整一个用起来简单一点的验证功能,毕竟在团队项目中,涉及任何类型的表单提交,数据还是需要验证一哈地。

以下内容转载自:https://www.cnblogs.com/guofeiji/p/5517094.html

当填写表单时,需要对填写的内容进行验证,检查数据是否符合要求,比如字符串的长度、日期的格式、数字等。WPF支持自定义验证规则,并提供可视化反馈,以便在输入无效值时向用户发出通知。

下面的示例将演示一个模拟员工信息录入的过程,如果年龄不再给定的输入范围内,将在文本框的后面显示一个红色的叹号,当鼠标移至错误文本框时,显示提示消息,提示用户正确的输入格式。

主要内容为:自定义验证规则、定义输入错误时控件的外观、定义样式触发器显示错误提示

自定义验证规则

可以继承ValidationRule类,重写Validate方法,实现自定义的验证规则

下面是年龄的验证规则的实现:

public class AgeRangeRule : ValidationRule
    {
        private int _min;
        private int _max;

        public AgeRangeRule()
        {

        }

        public int Min
        {
            get { return _min; }
            set { _min = value; }
        }

        public int Max
        {
            get { return _max; }
            set { _max = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            int age = 0;
            try
            {
                if (((string)value).Length > 0)
                    age = Int32.Parse((String)value);
            }
            catch (Exception e)
            {
                return new ValidationResult(false, "输入的数字无效!");
            }

            if ((age < Min) || (age > Max))
            {
                return new ValidationResult(false,
                  "输入的年龄范围必须在: " + Min + " - " + Max + "之间");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }
  
  View Code

定义输入错误时控件的外观

自定义的 ControlTemplate,它用于创建一个红色感叹号,以通知用户验证错误。 控件模板用于重新定义控件的外观。

<ControlTemplate x:Key="validationTemplate">
  <DockPanel>
    <AdornedElementPlaceholder/>
    <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
  </DockPanel>
</ControlTemplate>

定义样式触发器显示错误提示

显示错误消息的 ToolTip 是使用名为 textBoxInError 的样式创建的。 如果 HasError 的值是 true,则触发器将当前 TextBox 的工具提示设置为其第一个验证错误。 RelativeSource 设置为 Self,以引用当前元素。

<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>

控件绑定相应的模板和样式

<TextBox Name="textBox1" Width="50" FontSize="15"
         Validation.ErrorTemplate="{StaticResource validationTemplate}"
         Style="{StaticResource textBoxInError}"
         Grid.Row="1" Grid.Column="1" Margin="2">
  <TextBox.Text>
    <Binding Path="Age" Source="{StaticResource employee}"
             UpdateSourceTrigger="PropertyChanged" >
      <Binding.ValidationRules>
        <c:AgeRangeRule Min="21" Max="130"/>
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

当输入的年龄不在定义范围内时,控件的显示方式如下:

注:当数据绑定验证时,如果验证规则的ValidationStep属性设置为RawProposedValue或ConvertedProposedValue值时,在验证失败的情况下,数据不会更新到源,这也在情理之中,不合格的数据我们当然不接受。

关于数据验证的更多参考

【WPF】数据验证(博客园)

如何:实现绑定验证 – WPF | Microsoft Docs

WPF绑定数据验证(简书)

WPF MVVM从入门到精通8:数据验证(CSDN)

WPF点击按钮验证整个表单

在本教程中,您将学习如何在应用程序中添加一个验证字段,该字段可以告诉用户输入的凭据是否不正确。

用户数据几乎可以在包含这些表格的每个应用程序中进行验证。很有可能,如果您有使用WPF申请表的经验,则必须以某种能力来处理验证的实现。尽管手头上有大量选择,但大多数选择都是在“领域”发挥作用的。这样,在搜索“ WPF验证”时,您将学习如何使用IDataErrorInfo。但是,如果整个表单都需要验证怎么办?

WPF应用示例

例如,您有一个内置了授权的应用程序,以及类似以下的授权窗口:

JHRS开发框架WPF数据验证

下面是表单的xaml代码:

<Window>
  <Grid>         
    <TextBlock Text="Email: "/>
    <TextBox x:Name="EmailTextBox"/>
    <TextBlock Text="Password: "/>
    <TextBox x:Name="PasswordTextBox"/>
    <Button x:Name="LoginButton">Log in</Button>
  </Grid>
</Window>

当然,假设你的登录接口是这样的。

public class LogInService
  {
    public bool LogIn(string email, string password)
    {
        // In real life you will have some server communication here...but for now:
        return email.Equals("valid@email.com") && password.Equals("validPassword");
    }
  }

如建议的那样,当您执行查询搜索答案时,可以使用IDataErrorInfo禁用“登录”按钮(取决于验证结果)。这种方法将保证与服务器的大量交互。这就是我写这篇文章的原因:不能在所有密码字段或电子邮件更改上提交登录请求,因为它可能会阻止您的帐户或IP等问题。

答案:INotifyDataErrorInfo

值得庆幸的是,我们拥有INotifyDataErrorInfo和IDataErrorInfo,它们一旦实现便可以解决问题,因此您的模型可以如下所示:

public class MainWindowViewModel : INotifyDataErrorInfo
  {
    public string Email { get; set; } = "";
    public string Pass { get; set; } = "";
    public IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || (!HasErrors))
            return null;
        return new List<string>() {"Invalid credentials."};
    }
    public bool HasErrors { get; set; } = false;
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    public bool CheckCredentials()
    {
        HasErrors = !new LogInService().LogIn(Email, Pass);
        if (HasErrors)
        {
            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs("Email"));
            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs("Pass"));
        }
        else
        {
            return true;
        }
        return false;
    }
  }

错误由HasErrors显示。设置为一次检查凭据。实际错误由GetErrors返回。通过ErrorsChanged通知订户有关新错误。此外,我们补充了公共帮助方法CheckCredentials,可以使用LoginService从视图中调用它。看看这个例子:

private void LogInButton_Click(object sender, RoutedEventArgs e)
   {
       if (((MainWindowViewModel) DataContext).CheckCredentials())
       {
           Close();
       }   
   }

在XAML中,需要使用ValidatesOnNotifyDataErrors = True添加绑定:

<TextBox x:Name="EmailTextBox" Grid.Row="0" Grid.Column="1" Margin="5"
             Text="{Binding Email, ValidatesOnNotifyDataErrors=True}"/>
...
    <TextBox x:Name="PasswordTextBox" Grid.Row="1" Grid.Column="1" Margin="5"
             Text="{Binding Pass, ValidatesOnNotifyDataErrors=True}"/>

一旦启动该应用程序,并且在单击“登录”按钮时您一次输入了错误的密码/电子邮件,您将看到:

JHRS开发框架WPF数据验证

使用ValidationRule进行字段级别验证

现在让我们谈谈实际的现场水平验证。考虑一下我们在INotifyDataErrorInfo中所做的修改,并从ValidationRule方法开始。要查看电子邮件是否合法,我们将使用自己的验证规则。无需从头开始或重写您的正则表达式。我建议使用以下System.Net.Mail.MailAddress

public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        try
        {
            new MailAddress(value.ToString());
        }
        catch (Exception)
        {
            return new ValidationResult(false, "Please enter a valid email.");
        }
        return new ValidationResult(true, null);
    }

然后我们将其添加到XAML中:

<TextBox x:Name="EmailTextBox" Grid.Row="0" Grid.Column="1" Margin="5">
        <TextBox.Text>
            <Binding Path="Email" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <local:EmailValidationRule ValidationStep="RawProposedValue"/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

如果您已经开始开发自己的应用,并且与此类似,则您输入了错误的电子邮件地址:

JHRS开发框架WPF数据验证

输入时,它会更改,如果您输入有效的电子邮件,它将消失。

常见示例IDataErrorInfo

在线上有关此主题的大多数数据都引用了IDataErrorInfo。第一步是将其实现为视图模式:

public class MainWindowViewModel : IDataErrorInfo
  {
...
    public string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case "Email":
                    if (!IsValidEmail(Email))
                        return "Please enter a valid email.";
                    break;
            }
            return string.Empty;
        }
    }
    public string Error { get; }
    private bool IsValidEmail(string email)
    {
        try
        {
            new MailAddress(email);
        }
        catch (Exception)
        {
            return false;
        }
        return true;
    }
  }

仅使用辅助方法IsValidEmail时,我们的索引器会检查电子邮件字段。您必须在XAML中包含ValidatesOnDataErrors = True的绑定

在XAML中:

<TextBox x:Name="EmailTextBox" Grid.Row="0" Grid.Column="1" Margin="5"
             Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>

如果在开发完成后立即运行,将获得与使用早期方法获得的结果类似的结果。

显示验证错误文本

如果必须在文本框周围显示特定的消息而不是通用的红线,可以通过在XAML中覆盖ErrorTemplate来实现,如下所示:

<Validation.ErrorTemplate>
            <ControlTemplate>
                <StackPanel>
                    <AdornedElementPlaceholder/>
                    <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                </StackPanel>
            </ControlTemplate>
        </Validation.ErrorTemplate>

如果添加一些空间,则在测试表单时,其外观将如下所示:

JHRS开发框架WPF数据验证

写在最后 – JHRS开发框架

WPF提供了许多工具来验证表单。如果您想发表您的想法或提出建议,请在以下评论部分中进行。

从WPF点击按钮验证整个表单到最后,内容翻译自:https://dzone.com/articles/wpf-validation-how-to-validate-the-whole-form-on-t

WPF数据验证这篇文章就这样烂尾了,不过找了一些参考,相信应该可以自己完整的实现WPF数据验证,下一篇将说一下JHRS开发框架中引入了Prism后,ViewModel相互传参的问题。

本系列相关阅读

  1. WPF企业级开发框架搭建指南(启示录)
  2. JHRS开发框架之基础类库
  3. JHRS开发框架之第三方框架选型
  4. JHRS开发框架之WPF调用Web API封装
  5. JHRS开发框架之客户端入口项目
  6. JHRS开发框架之各子系统如何整合
  7. JHRS开发框架之怎样设计合理的ViewModel基类
  8. JHRS开发框架之公用组件用户控件的封装
  9. JHRS开发框架之建议遵循的一些建目录文件原则
  10. JHRS开发框架之WPF数据验证
  11. JHRS开发框架之ViewModel相互传参和弹框回传参的解决办法
  12. JHRS开发框架之踩坑记(终章)
退出移动版