WPF数据验证

1、ValidationRule 验证

ValidationRule:是通过ValidationRule中的的Validate方法来验证我们绑定的属性。所以我们的用法是继承ValidationRule,重写他的Validate方法。示例

public class RequiredRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            if (value == null)
                return new ValidationResult(false, "不能为空值!");
            if (string.IsNullOrEmpty(value.ToString()))
                return new ValidationResult(false, "不能为空字符串!");

            return new ValidationResult(true, null);
        }
    }

而XAML中需要把错误信息显示出来。

<Window.Resources>
        <ControlTemplate x:Key="ErrorTemplate">
            <Border BorderBrush="Red" BorderThickness="1">
                <AdornedElementPlaceholder/>
            </Border>
        </ControlTemplate>
        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}">
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBlock Text="姓名"/>
        <TextBox>
            <TextBox.Text>
                <Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
                    <Binding.ValidationRules>
                        <ValidationRules:RequiredRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBlock Text="年龄"/>
        <TextBox >
            <TextBox.Text>
                <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
                    <Binding.ValidationRules>
                        <ValidationRules:GreaterThanRule Number="10"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
    </StackPanel>

这样显示的错误信息就会以 ToolTip和红色边框的形式显示出来。但这边如果又在TextBox里面设置ToolTip那么就会优先选择TextBox里的,也就是Style中的ToolTip遇到错误信息是不会显示出来的,而是显示TextBox中的ToolTip。所以我们可以改善一下显示的模版来解决这个问题。

<ControlTemplate x:Key="ErrorTemplate">
            <DockPanel LastChildFill="true">
                <Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                            ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
                    <TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
                    </TextBlock>
                </Border>
                <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                    <Border BorderBrush="red" BorderThickness="1" />
                </AdornedElementPlaceholder>
            </DockPanel>
        </ControlTemplate>

2、Exception 验证

Exception :我们xaml中绑定的对象是属性。所以Exception验证,就是通过属性的改变来判断是否正常。如:

 public int Age
        {
            get { return _age; }
            set
            {
                if (value > 200)
                {
                    throw new Exception("年龄不能大于200");
                }
                _age = value;
            }
        }

同样跑出的异常在Xaml中也要显示下。XAML同上。这种方式就会破坏POCO的设计原则。

3、IDataErrorInfo 验证

IDataErrorInfo:这个验证是通过我们的实体对象继承IDataErrorInfo来实现的。这里声明的this索引器来访问类的成员。

 public class BaseDataErrorInfo : IDataErrorInfo
    {
        private string _error;

        public string this[string columnName]
        {
            get { return GetErrorFor(columnName); }
        }

        public string Error
        {
            get { return _error; }
            set { _error = value; }
        }

        public virtual string GetErrorFor(string columnName)
        {
            return string.Empty;
        }
    }
public class Person : BaseDataErrorInfo
    {
        public string Name { get; set; }

        public override string GetErrorFor(string columnName)
        {
            if (columnName == "Name")
                if (string.IsNullOrEmpty(Name))
                    return "Name 不能为空";

            return base.GetErrorFor(columnName);
        }

    }

4、IDataErrorInfo带有数据校验功能的验证

/// <summary>
/// 带有数据校验功能的通知基类
/// </summary>
public class ViewModelValidationBase : ViewModelBase, IDataErrorInfo
{
/// <summary>
/// 需要校验的属性集合
/// </summary>
private List<string> validationKeys = new List<string>();
/// <summary>
/// 错误信息字典
/// </summary>
private Dictionary<string, string> errorDic = new Dictionary<string, string>();
/// <summary>
/// 是否开始校验,以此控制IDataErrorInfo接口校验的时候界面刚初始化即开始校验
/// </summary>
public bool IsBeginValidation { get; set; }
public string this[string columnName]
{
get
{
if (!IsBeginValidation)
{
return string.Empty;
}
var vc = new ValidationContext(this, null, null);
vc.MemberName = columnName;
var res = new List<ValidationResult>();
var result = Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null), vc, res);
if (res.Count > 0)
{
string errorMessage = string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
AddErrorDic(columnName, errorMessage);
return errorMessage;
}
RemoveErrorDic(columnName);
return string.Empty;
}
}

public string Error => string.Join(Environment.NewLine, errorDic.Values.ToArray());
/// <summary>
/// 添加进行校验的属性集合
/// </summary>
/// <param name="keys"></param>
protected virtual void ValidationKey(string[] keys)
{
if (keys == null)
{
return;
}
foreach (var item in keys)
{
validationKeys.Add(item);
}
}
/// <summary>
/// 强制进行以此校验
/// </summary>
protected void Validation()
{
if (validationKeys != null)
{
foreach (var item in validationKeys)
{
RaisePropertyChanged(item);
}
}
}

private void AddErrorDic(string key, string value)
{
if (!errorDic.Keys.Contains(key))
{
errorDic.Add(key, value);
}
}
private void RemoveErrorDic(string key)
{
errorDic.Remove(key);
}
}

 

其中ViewModelBase类我使用的是MVVMLight中的通知基类。
使用的时候继承该类,然后使用属性IsBeginValidation控制校验的时机,方法 ValidationKey(string[] keys) 添加需要校验的属性,方法Validation()可以触发校验,属性Error显示校验信息,为空则校验正确,不为空校验错误。
校验规则是使用特性的方式,引用名称空间

using System.ComponentModel.DataAnnotations;

/// <summary>
/// 获取或设置
/// </summary>
private string name;
/// <summary>
/// 获取或设置
/// </summary>
[Required(ErrorMessage = "用户名称不能为空")]
public string Name
{
get { return name; }
set { Set<string>(ref name, value, "Name"); }
}

 

posted @ 2021-12-06 15:02  zyl2  阅读(399)  评论(0)    收藏  举报