将命令canexecute绑定到IDataErrorInfo

时间:2015-02-13 13:40:16

标签: c# wpf validation mvvm

修改

我可能会稍微复杂一些,所以让它保持简单。如果将整数绑定到文本框,如果在文本框中键入非法字符,它将获得验证异常。如何根据属性是否具有验证异常来禁用按钮。

原始问题#

我使用MVVM方法在WPF中创建应用程序,但没有任何框架。

我的模型类实现了IDataErrorInfo,如果发生错误,则都具有HasError属性和< propertyName,ErrorMessage>。如果HasError属性在我的命令上更改了我的RaiseCanExecuteChanged以重新评估我们现在是否可以保存。

这样可以正常工作,但仅适用于

等显式数据注释
  [MaxLength(3,ErrorMessage = "The text can't be longer than 3")]
  [CustomRequiredAttribute]
  public string CountryCode
  {
     get { return m_CountryCode; }
     set { SetProperty(ref m_CountryCode, value); }
  }
  public string m_CountryCode;

另一方面,如果我将一个Integer绑定到文本框并输入非法字符(如字母),则OnValidate函数不会触发,因此错误不会添加到我的集合中。

如何捕获所有验证错误并添加到我的收藏中?

string IDataErrorInfo.this[string propertyName]
{
   get
   {
      var error = OnValidate(propertyName);

      return error;
   }
}

这是我的CanExecute

  protected override bool CanHandleSaveCommand()
  {
     return !Feeds.Any(e => e.HasErrors) && IsEdited;
  }

这样你可以得到完整的图片是OnValidate方法,它可以正常工作

protected virtual string OnValidate(string propertyName)
  {
     if (string.IsNullOrEmpty(propertyName))
     {
        throw new ArgumentException("Invalid property name", propertyName);
     }

     var error_summary = new StringBuilder();
     PropertyInfo property_info = GetType().GetProperty(propertyName);
     var value = property_info.GetValue(this);
     var validation_errors = new List<ValidationResult>();
     var is_valid = Validator.TryValidateProperty(
         value,
         new ValidationContext(this, null, null)
         {
            MemberName = propertyName
         },
         validation_errors);

     if (is_valid)
     {
        if (Errors.ContainsKey(propertyName))
        {
           Errors.Remove(propertyName);
           PropertyChanged(this, new PropertyChangedEventArgs("HasErrors"));
           HasErrorsChanged(this, EventArgs.Empty);
        }
     }
     else
     {
        validation_errors.ForEach(e => error_summary.Append(e.ErrorMessage));

        if (Errors.ContainsKey(propertyName))
           Errors[propertyName] = error_summary.ToString();
        else
           Errors.Add(propertyName, error_summary.ToString());

        PropertyChanged(this, new PropertyChangedEventArgs("HasErrors"));
        HasErrorsChanged(this, EventArgs.Empty);

     }

     return error_summary.ToString();
  }

2 个答案:

答案 0 :(得分:2)

我终于找到了我想要的答案。正如我之前所说,如果您输入非法字符,您的财产将永远不会被设置。 WPF框架抛出转换错误异常并将其添加到Validation.Errors集合中,但不会调用任何自定义验证代码。您必须改为使用UpdateSourceExceptionFilter Property

<TextBox>
   <TextBox.Text>
      <Binding 
         UpdateSourceExceptionFilter="ReturnExceptionHandler"
         Path="CurrencyPotens"
         UpdateSourceTrigger="PropertyChanged"
         ValidatesOnDataErrors="True"></Binding>
    </TextBox.Text>
</TextBox>

在代码隐藏中,我可以将绑定对象强制转换为NotifyPropertyChanged类并添加Error,这反过来会导致我的ICommands CanExecute重新评估。

  public object ReturnExceptionHandler(object bindingExpression, Exception exception)
  {
     BindingExpression be = bindingExpression as BindingExpression;
     var boundItem = be.DataItem;
     ((Wrapper.NotifyPropertyChanged)boundItem).Errors.Add(be.ResolvedSourcePropertyName, exception.Message);

     return exception.Message;
  }

现在我无法使用我的MVVM方法,因此我在代码隐藏中遇到了一些代码。

答案 1 :(得分:0)

您的代码未被调用,因为UI无法识别是否存在某些错误。我通常做的是在我的VM中实现INotifyDataErrorInfo。更改属性后,我在属性设置器中调用value。然后,如果需要,我会解雇INotifyDataErrorInfo.ErrorsChangedEvent。因此,UI知道错误并做出相应的反应

当然你仍然可以在幕后使用IDataErrorInfo。希望这有帮助

修改

我明白了你的意思。我现在无法找到解决方案,但可能会给你一个方向。我建议查看Overriding metadata techniqueDependency propery callbacks。因此,您覆盖TextBox.TextProperty元数据并使用自定义回调来设置错误。

当我有空闲时间时,我会回到这个问题