【问题标题】:Binding a commands canexecute to IDataErrorInfo绑定命令可以执行到 IDataErrorInfo
【发布时间】:2015-02-13 13:40:15
【问题描述】:

编辑

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

原始问题#

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

我的模型类实现了 IDataErrorInfo,如果发生错误,它们都有一个 HasError 属性和一个 的字典。如果 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();
  }

【问题讨论】:

  • 请检查我的编辑

标签: c# wpf validation mvvm


【解决方案1】:

我终于找到了我正在寻找的答案。正如我之前所说,如果您输入非法字符,则永远不会设置您的属性。 WPF 框架引发转换错误异常并添加到 Validation.Errors 集合中,但不会调用任何自定义验证代码。您必须改用UpdateSourceExceptionFilter Property

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

在代码隐藏中,我可以将绑定的对象转换为我的 NotifyPropertyChanged 类并添加错误,这反过来会导致我的 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 方法一起使用,所以我在代码隐藏中遇到了一些小代码。

【讨论】:

    【解决方案2】:

    您的代码没有被调用,因为 UI 不知道是否有错误。我通常做的是在我的虚拟机中实现INotifyDataErrorInfo。更改属性时,我在属性设置器中 vaidate value。然后,如果需要,我会解雇INotifyDataErrorInfo.ErrorsChangedEvent。因此 UI 知道错误并做出相应的反应

    当然,您仍然可以在幕后使用IDataErrorInfo。希望这会有所帮助

    编辑

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

    我有空再讨论这个问题

    【讨论】:

    • 但是用于验证的 INotifyDataErrorInfo 不是像开始日期不能在结束日期之后出现吗? WPF 根据类型进行验证,即整数不能包含“Hello”我可以显示这些错误但你如何绑定到它们?
    • 抱歉,我不确定我是否理解您想要实现的目标。如果您只需要在某处显示这些错误,请使用 &lt;Validation.ErrorTemplate&gt; like here
    • 我可能有些混淆了我的问题,但是这就是我正在做的事情,但除了显示存在错误之外,我还需要禁用我的保存按钮。所有这些都适用于我编写的数据注释。但不是当我在绑定到整数的文本框中输入一个字母时
    • 如果您已经在实现INotifyPropertyChangedIDataErrorInfo,则添加一个布尔值来跟踪是否存在错误,并且每当您更新验证时,为该属性触发PropertyChanged 事件。将该属性绑定到按钮 IsEnabled 属性
    • 这正是我正在做的,但是当您在整数文本框中键入非法字符时,整数属性永远不会设置(怎么可能,“你好”不能转换为整数) 并且您无法对 set 属性进行评估,并且永远不会触发 IDataErrorInfo。那么如何绑定到 WPF 框架拾取的转换错误呢?
    猜你喜欢
    • 2011-04-23
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 2013-08-16
    • 1970-01-01
    相关资源
    最近更新 更多