WPF:数据验证(3)

地精撕裂者
• 阅读 4664

BusinessLayerValidation业务层逻辑验证

练习:

  1. 如何在业务层数据视图类编写验证代码
  2. Xaml中使用DataErrorValidationRule

WPF:数据验证(3)

WPF:数据验证(3)
样式中工具提示显示验证错误信息,与之前代码一样

<!--The tool tip for the TextBox to display the validation error message.-->
<Style x:Key="TextBoxInError" TargetType="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>

此处多了ValidatesOnExceptions="True"

  1. 通过设置此属性,可以以另一种方式显式使用 ExceptionValidationRule 元素。
  2. ExceptionValidationRule 类是内置的验证规则,它检查在源属性更新过程中引发的异常。 如果引发异常,则绑定引擎将对异常创建 ValidationError 并将其添加到绑定元素的 Validation.Errors 集合中。
<TextBox Style="{StaticResource TextBoxInError}">
    <TextBox.Text>
        <!--By setting ValidatesOnExceptions to True, it checks for exceptions
        that are thrown during the update of the source property.
        An alternative syntax is to add <ExceptionValidationRule/> within
        the <Binding.ValidationRules> section.-->
        <Binding Path="Age" Source="{StaticResource Data}"
                 ValidatesOnExceptions="True"
                 UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <!--DataErrorValidationRule checks for validation 
                    errors raised by the IDataErrorInfo object.-->
                <!--Alternatively, you can set ValidationOnDataErrors="True" on the Binding.-->
                <DataErrorValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

DataErrorValidationRule:表示一个规则,该规则检查由源对象的 IDataErrorInfo 实现所引发的错误。

使用 WPF 数据绑定模型可以将 ValidationRules 与 Binding 对象相关联。 如果源对象实现 IDataErrorInfo 接口,则可以使用内置的规则  DataErrorValidationRule 来检查由 IDataErrorInfo 实现引发的错误。

再来看实现IDataErrorInfo接口类

public class Person : IDataErrorInfo
{
    public int Age { get; set; }
    public string Error => null;

    public string this[string name]
    {
        get
        {
            string result = null;

            if (name == "Age")
            {
                if (Age < 0 || Age > 150)
                {
                    result = "Age must not be less than 0 or greater than 150.";
                }
            }
            return result;
        }
    }
}

ValidationItemsInItemsControl在一组项中的多项验证

练习:

  1. 价格为正整数的验证类
  2. 大于现在的日期验证类
  3. BindingGroup的事务验证结果

WPF:数据验证(3)

WPF:数据验证(3)

HeaderedContentControl样式:

<Style TargetType="HeaderedContentControl">
    <Setter Property="Margin" Value="2"/>
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="HeaderedContentControl">
                <DockPanel LastChildFill="False">
                    <ContentPresenter ContentSource="Header" DockPanel.Dock="Left" Focusable="False" VerticalAlignment="Center"/>
                    <ContentPresenter ContentSource="Content" Margin="5,0,0,0" DockPanel.Dock="Right" VerticalAlignment="Center"/>
                </DockPanel>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

正整数验证xaml

<HeaderedContentControl Header="Price">
    <TextBox Name="priceField"  Width="150">
        <TextBox.Text>
            <Binding Path="Price" Mode="TwoWay" >
                <Binding.ValidationRules>
                    <local:PriceIsAPositiveNumber/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</HeaderedContentControl>

大于现在日期xaml

<HeaderedContentControl Header="Date Offer Ends">
    <TextBox Name="dateField" Width="150" >
        <TextBox.Text>
            <Binding Path="OfferExpires" StringFormat="d" >
                <Binding.ValidationRules>
                    <local:FutureDateRule/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</HeaderedContentControl>

容器的验证错误控件及绑定源加载

<StackPanel Name="stackPanel1"  Margin="10" 
      Loaded="StackPanel1_Loaded"
      Validation.Error="ItemError">

绑定组xaml

<StackPanel.BindingGroup>
    <BindingGroup NotifyOnValidationError="True">
        <BindingGroup.ValidationRules>
            <local:ValidateDateAndPrice ValidationStep="ConvertedProposedValue" />
        </BindingGroup.ValidationRules>
    </BindingGroup>
</StackPanel.BindingGroup>

BindingGroup.NotifyOnValidationError:获取或设置在 ValidationRule 的状态更改时是否发生 Validation.Error 事件.

示例创建 BindingGroup 并将 NotifyOnValidationError 设置为 true,以便应用程序可以在 ValidationRule 失败时处理 Validation.Error 事件。

public class ValidateDateAndPrice : ValidationRule
{
    // Ensure that an item over $100 is available for at least 7 days.
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var bg = value as BindingGroup;

        // Get the source object.
        var item = bg?.Items[0] as PurchaseItem;

        object doubleValue;
        object dateTimeValue;

        // Get the proposed values for Price and OfferExpires.
        var priceResult = bg.TryGetValue(item, "Price", out doubleValue);
        var dateResult = bg.TryGetValue(item, "OfferExpires", out dateTimeValue);

        if (!priceResult || !dateResult)
        {
            return new ValidationResult(false, "Properties not found");
        }

        var price = (double) doubleValue;
        var offerExpires = (DateTime) dateTimeValue;

        // Check that an item over $100 is available for at least 7 days.
        if (price > 100)
        {
            if (offerExpires < DateTime.Today + new TimeSpan(7, 0, 0, 0))
            {
                return new ValidationResult(false, "Items over $100 must be available for at least 7 days.");
            }
        }

        return ValidationResult.ValidResult;
    }
}
  1. 将 ValidationStep 设置为 ConvertedProposedValue,这样,当该验证规则运行时, Validate 方法便可访问属于源属性类型的值。
  2. 当 PriceIsAPositiveNumber 和 FutureDateRule 规则运行时,每个 Validate 方法中的值均为字符串,原因是先运行规则,然后才将这些值转换为各自的类型。
public class PriceIsAPositiveNumber : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        try
        {
            var price = Convert.ToDouble(value);

            if (price < 0)
            {
                return new ValidationResult(false, "Price must be positive.");
            }
            return ValidationResult.ValidResult;
        }
        catch (Exception)
        {
            // Exception thrown by Conversion - value is not a number.
            return new ValidationResult(false, "Price must be a number.");
        }
    }
}
internal class FutureDateRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        DateTime date;
        try
        {
            date = DateTime.Parse(value?.ToString());
        }
        catch (FormatException)
        {
            return new ValidationResult(false, "Value is not a valid date.");
        }
        return DateTime.Now.Date > date
            ? new ValidationResult(false, "Please enter a date in the future.")
            : ValidationResult.ValidResult;
    }
}

关键执行组验证代码:

private void Submit_Click(object sender, RoutedEventArgs e)
{
    if (stackPanel1.BindingGroup.CommitEdit())
    {
        MessageBox.Show("Item submitted");
        stackPanel1.BindingGroup.BeginEdit();
    }
}

BindingGroup.CommitEdit :运行所有 ValidationRule 对象,并且在所有验证规则都成功时,更新绑定源。

BindingGroup.BeginEdit :开始 BindingGroup 中源上的编辑事务。

以下为放弃验证按钮

private void Cancel_Click(object sender, RoutedEventArgs e)
{
    // Cancel the pending changes and begin a new edit transaction.
    stackPanel1.BindingGroup.CancelEdit();
    stackPanel1.BindingGroup.BeginEdit();
}

如果 BindingGroup 中的源支持放弃挂起的更改,则可以调用 BeginEdit 以开始编辑事务,调用 CommitEdit 以保存挂起的更改,调用 CancelEdit 以放弃挂起的更改。

最后,容器加载Validation.Error 附加事件:当所绑定的元素遇到验证错误时发生,但只适用于将 NotifyOnValidationError 值设置为 true 的绑定。

// This event occurs when a ValidationRule in the BindingGroup
// or in a Binding fails.
private void ItemError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        MessageBox.Show(e.Error.ErrorContent.ToString());
    }
}

扩展知识:ValidationStep 枚举:指定 ValidationRule 何时运行。

  1. 此规则的 ValidationStep 设置为 ConvertedProposedValue,这样,当其运行时, Validate 方法将能访问具有源属性类型的值。
  2. 当 PriceIsAPositiveNumber 和 FutureDateRule 规则运行时,每个 Validate 方法中的值均为字符串,原因是 ValidationStep 的默认值为 RawProposedValue。 因此,规则会在将值转换为其各自的类型之前运行。
  3. 在 Validate 方法中,Price 属性的类型为 Double,OfferExpires 属性的类型为 DateTime。 在 ValidationRule 运行之前,字符串已转换为其各自的类型。
点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
Tp5安全篇入门
输入安全设置public目录为唯一对外访问目录,不能把资源文件放入到应用目录;使用框架提供的请求变量获取方法(Request类的param方法及input助手函数)而不是原生系统变量获取用户输入的数据;使用验证类或者验证方法对业务数据设置必要的验证规则;设置安全过滤函数对用户输入的数据进行过滤处理。
Stella981 Stella981
3年前
Python之路【第十七篇】:Django【进阶篇 】(转自银角大王博客)
Model到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:创建数据库,设计表结构和字段使用MySQLdb来连接数据库,并编写数据访问层代码业务逻辑层去调用数据访问层执行数据库操作!(https://oscimg.oschina.net/oscnet/2f863fee384e3d877
Stella981 Stella981
3年前
Hyperledger Fabric如何启用双向TLS安全通信?
HyperlederFabric区块链支持在通信节点之间启用TLS传输层安全通信,TLS支持单向验证仅验证服务节点身份,或双向验证同时验证服务节点和客户端节点的身份。本文将介绍如何在HyperledgerFabric网络中启用双向TLS安全通信。HyperledgerFabric链码与应用开发相关教程:Hype
Stella981 Stella981
3年前
C#里面BLL、Model、DAL、UI层
C三层架构分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)再加上实体类库(Model)1、实体类库(Model),主要存放数据库中的表字段。操作:(1)先建立实体类库Model,打开项目,在解决方案中右键》添加》新建项目》选中类库》改名Model》确定(2)选中Model类库》ShiftALT
Stella981 Stella981
3年前
ASP.NET MVC 5
MVC代表:_模型__\__视图__\__控制器_。MVC是一个架构良好并且易于测试和易于维护的开发模式。基于MVC模式的应用程序包含:·Models:表示该应用程序的数据并使用验证逻辑来强制实施业务规则的数据类。·Views:应用程序动态生成HTML所使用的模板文件。·Controllers:
Stella981 Stella981
3年前
Spring 12 种 常用注解!
1.声明bean的注解@Component组件,没有明确的角色@Service在业务逻辑层使用(service层)@Repository在数据访问层使用(dao层)@Controller在展现层使用,控制器的声明(C)2.注入bean的注解@Autowired:由Spring提供@Inj
Wesley13 Wesley13
3年前
MySQL数据安全策略
0、导读MySQL被运用于越来越多的业务中,在关键业务中对数据安全性的要求也更高,如何保证MySQL的数据安全?MySQL被运用于越来越多的业务中,在关键业务中对数据安全性的要求也更高,如何保证MySQL的数据安全。数据安全如果只靠MySQL应用层面显然是不够的,是需要在多个层面来保护的,包括网络、系统、逻辑应用层、数据库层等。
Easter79 Easter79
3年前
Spring中@Controller、@Repository、@Service、@Component注解的作用详解
Spring中使用在类上的常用注解有@Controller、@Repository、@Service、@Component,下面分别详细介绍一下他们的作用:1、@Controller:用于标注控制层服务。2、@Repository:用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件。3、@Service:用于标注业务逻辑层服务,主要
马尚 马尚
1年前
使用JavaScript破解数字验证码
数字验证码通常用于网站或应用程序的用户身份验证和安全性保护。本文将介绍如何使用JavaScript编写代码来破解数字验证码,以便于自动化处理验证码验证过程。1.分析验证码页面首先,我们需要分析网站或应用程序的验证码页面,了解验证码是如何呈现的以及需要提交的