validation失败时禁用保存按钮

正如你可能从标题中看到的那样,我将要问一些之前被问过很多次的事情。 但是,在阅读了所有这些其他问题之后,我找不到合适的解决方案来解决我的问题。

我有一个基本validation的模型类:

partial class Player : IDataErrorInfo { public bool CanSave { get; set; } public string this[string columnName] { get { string result = null; if (columnName == "Firstname") { if (String.IsNullOrWhiteSpace(Firstname)) { result = "Geef een voornaam in"; } } if (columnName == "Lastname") { if (String.IsNullOrWhiteSpace(Lastname)) { result = "Geef een familienaam in"; } } if (columnName == "Email") { try { MailAddress email = new MailAddress(Email); } catch (FormatException) { result = "Geef een geldig e-mailadres in"; } } if (columnName == "Birthdate") { if (Birthdate.Value.Date >= DateTime.Now.Date) { result = "Geef een geldige geboortedatum in"; } } CanSave = true; // this line is wrong return result; } } public string Error { get { throw new NotImplementedException();} } } 

每次属性更改时都会执行此validation(因此每次用户在文本框中键入一个字符时):

  

这很完美。 validation发生(绑定的PropertyChanged代码在CurrentPlayer属性上的VM中完成,该属性是Player的对象)。

我现在要做的是在validation失败时禁用保存按钮。

首先,最简单的解决方案似乎可以在这个post中找到:
使用IDataErrorInfo在validation期间启用“禁用保存”按钮

  1. 如果我想遵循公认的解决方案,我必须编写两次validation码,因为我不能简单地使用索引器。 编写双重代码绝对不是我想要的,所以这不是我的问题的解决方案。
  2. 该线程的第二个答案听起来非常有希望,但问题是我有多个字段需要validation。 这样,所有内容都依赖于最后一个已检查的属性(因此,如果正确填充该字段, CanSave将为true,即使其他字段仍然无效)。

我发现的另一个解决方案是使用ErrorCount属性。 但是,由于我在每次更改属性时都会进行validation(对于每个类型的角色也是如此),这也是不可能的 – 我怎么知道何时增加/减少ErrorCount

什么是解决这个问题的最佳方法?

谢谢

我已经实现了上面评论中显示的地图方法,在C#中这称为一个字典 ,其中我使用匿名方法进行validation:

 partial class Player : IDataErrorInfo { private delegate string Validation(string value); private Dictionary columnValidations; public List Errors; public Player() { columnValidations = new Dictionary(); columnValidations["Firstname"] = delegate (string value) { return String.IsNullOrWhiteSpace(Firstname) ? "Geef een voornaam in" : null; }; // Add the others... errors = new List(); } public bool CanSave { get { return Errors.Count == 0; } } public string this[string columnName] { get { return this.GetProperty(columnName); } set { var error = columnValidations[columnName](value); if (String.IsNullOrWhiteSpace(error)) errors.Add(error); else this.SetProperty(columnName, value); } } } 

本文http://www.asp.net/mvc/tutorials/older-versions/models-%28data%29/validating-with-the-idataerrorinfo-interface-cs将单个validation移动到属性中:

 public partial class Player : IDataErrorInfo { Dictionary _errorInfo; public Player() { _errorInfo = new Dictionary(); } public bool CanSave { get { return _errorInfo.Count == 0; } public string this[string columnName] { get { return _errorInfo.ContainsKey(columnName) ? _errorInfo[columnName] : null; } } public string FirstName { get { return _firstName;} set { if (String.IsNullOrWhiteSpace(value)) _errorInfo.AddOrUpdate("FirstName", "Geef een voornaam in"); else { _errorInfo.Remove("FirstName"); _firstName = value; } } } } 

(您必须处理Dictionary AddOrUpdate扩展方法)。 这类似于错误计数的想法。

此方法适用于数据注释。 您还可以将“IsValid”属性绑定到“保存”按钮以启用/禁用。

 public abstract class ObservableBase : INotifyPropertyChanged, IDataErrorInfo { #region Members private readonly Dictionary errors = new Dictionary(); #endregion #region Events ///  /// Property Changed Event ///  public event PropertyChangedEventHandler PropertyChanged; #endregion #region Protected Methods ///  /// Get the string name for the property ///  ///  ///  ///  protected string GetPropertyName(Expression> expression) { var memberExpression = (MemberExpression) expression.Body; return memberExpression.Member.Name; } ///  /// Notify Property Changed (Shorted method name) ///  ///  ///  protected virtual void Notify(Expression> expression) { string propertyName = this.GetPropertyName(expression); PropertyChangedEventHandler handler = this.PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } ///  /// Called when [property changed]. ///  ///  /// The expression. protected virtual void OnPropertyChanged(Expression> expression) { string propertyName = this.GetPropertyName(expression); PropertyChangedEventHandler handler = this.PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion #region Properties ///  /// Gets an error message indicating what is wrong with this object. ///  public string Error => null; ///  /// Returns true if ... is valid. ///  ///  /// true if this instance is valid; otherwise, false. ///  public bool IsValid => this.errors.Count == 0; #endregion #region Indexer ///  /// Gets the  with the specified column name. ///  ///  /// The . ///  /// Name of the column. ///  public string this[string columnName] { get { var validationResults = new List(); string error = null; if (Validator.TryValidateProperty(GetType().GetProperty(columnName).GetValue(this), new ValidationContext(this) { MemberName = columnName }, validationResults)) { this.errors.Remove(columnName); } else { error = validationResults.First().ErrorMessage; if (this.errors.ContainsKey(columnName)) { this.errors[columnName] = error; } else { this.errors.Add(columnName, error); } } this.OnPropertyChanged(() => this.IsValid); return error; } } #endregion }