WPF进阶技巧和实战08-依赖属性与绑定02 (4)

WPF通过接口IDataErrorInfo和INotifyDataErrorInfo,允许构建报告错误的对象而不是直接抛出异常。两个接口具有相同的目标,即用更加人性化的错误通知系统来替代未处理的异常。IDataErrorInfo是初始的错误跟踪接口,为了是WPF向下兼容。INotifyDataErrorInfo接口具有同样的功能,但界面更加丰富。

public class MainWindowViewModel : NotifyPropertyBase, INotifyDataErrorInfo {     private decimal? _productPrice;     public decimal? ProductPrice         {             get => _productPrice;             set             {                 if (value.HasValue && value.Value < 0)                 {                     //throw new Exception("ProductPrice 不能小于0");                     SetError("ProductPrice", new List<string> { "ProductPrice 不能小于0" });                 }                 else                 {                     ClearErrors("ProductPrice");                 }                 _productPrice = value;                 OnPropertyChanged("ProductPrice");             }         }     private Dictionary<string, List<string>> DictError = new Dictionary<string, List<string>>();     private void SetError(string propertyName, List<string> propertyErrors)         {             DictError.Remove(propertyName);             DictError.Add(propertyName, propertyErrors);             if (ErrorsChanged != null)             {                 ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));             }         }     private void ClearErrors(string propertyName)         {             DictError.Remove(propertyName);             if (ErrorsChanged != null)             {                 ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));             }         }     /// <summary>     /// 用于指示数据对象是否包含错误信息     /// </summary>     public bool HasErrors => DictError.Keys.Count > 0;     /// <summary>     /// 在添加和删除错误时发生     /// </summary>     public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;     /// <summary>     /// 提供完整的错误信息内容     /// </summary>     /// <param></param>     /// <returns></returns>     public IEnumerable GetErrors(string propertyName)     {         if (string.IsNullOrEmpty(propertyName))         {             return DictError.Values;         }         if (DictError.ContainsKey(propertyName))         {             return DictError[propertyName];         }         return null;     } } <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="200,200,0,0">     <TextBox.Text>         <Binding Path="ProductPrice" ValidatesOnNotifyDataErrors="True" NotifyOnValidationError="True"/>     </TextBox.Text> </TextBox>

通过上述两种形式实现异常通知,但是他们之间有本质的区别:触发异常时,不会在数据对象中更新属性。但是使用INotifyDataErrorInfo接口时,允许使用非法值,但是会标记出来,数据对象会被更新,可以使用通知或者事件告知用户。

自定义验证规则

应用自定义规则的方法和应用自定义转化器的方法类似。继承自ValidationRule,并重写Validate()方法。

public class CustomValidation : ValidationRule {     private decimal? _minValue = 0;     private decimal? _maxValue = int.MaxValue;     public decimal? MinValue     {         get => _minValue;         set => _minValue = value;     }     public decimal? MaxValue     {         get => _maxValue;         set => _maxValue = value;     }     public override ValidationResult Validate(object value, CultureInfo cultureInfo)     {         decimal price = 0;         try         {             string strValue = value.ToString();             if (!string.IsNullOrEmpty(strValue))             {                 price = decimal.Parse(strValue, cultureInfo);             }         }         catch (Exception)         {             return new ValidationResult(false, "非法数据");         }         if (price < _minValue || price > _maxValue)         {             return new ValidationResult(false, "非法数据");         }         return new ValidationResult(true, null);     } } <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="200,300,0,0">     <TextBox.Text>         <Binding Path="ProductPrice">             <Binding.ValidationRules>                 <local:CustomValidation MaxValue="99.99"/>             </Binding.ValidationRules>         </Binding>     </TextBox.Text> </TextBox>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjzpy.html