2016-11-16 11 views
0

私はmvvmを使用してwpfアプリケーションを開発する初心者です。だから私が箱から何かを求めているのならば、無視してください。データアノテーションを使用してデータを検証するモデルクラスがあります。ここでWpfでdataAnnonationの正規表現の検証属性を使用するMvvm IdataErrorInfo

はモデルクラスのコードの一部が

/// <summary> 
    /// The firstname of the person. 
    /// </summary> 
    [Required(AllowEmptyStrings = false, ErrorMessage = "First name must not be empty.")] 
    [MaxLength(20, ErrorMessage = "Maximum of 20 characters is allowed.")] 
    public string Firstname { get; set; } 

    /// <summary> 
    /// The lastname of the person. 
    /// </summary> 
    [Required(AllowEmptyStrings = false, ErrorMessage = "Address must not be empt.")] 
    public string Address { get; set; } 

    [MaxLength(20, ErrorMessage = "Maximum of 20 characters is allowed.")] 
    public string PhoneNum { get; set; } 

である私の検証は、XAMLに完全に罰金拘束正常に動作し、「必要とmaxLengthの属性」の場合はテキストボックス内のエラーを示しています。今では正規表現属性をモデルクラスの電話番号に使用したいと考えています。

[RegularExpression("^[0-9]*$", ErrorMessage = "Phone Num must be numeric")] 
[MaxLength(20, ErrorMessage = "Maximum of 20 characters is allowed.")] 
public string PhoneNum { get; set; } 

のようにここに私のBaseModelクラスにIDataErrorInfoのコードがあります。

using Annotations; 

/// <summary> 
/// Abstract base class for all models. 
/// </summary> 
public abstract class BaseModel : INotifyPropertyChanged, IDataErrorInfo 
{ 
    #region constants 

    private static List<PropertyInfo> _propertyInfos; 

    #endregion 

    #region events 

    /// <summary> 
    /// Occurs when a property value changes. 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    #region constructors and destructors 

    /// <summary> 
    /// Default constructor. 
    /// </summary> 
    public BaseModel() 
    { 
     InitCommands(); 
    } 

    #endregion 

    #region explicit interfaces 

    /// <summary> 
    /// Gets an error message indicating what is wrong with this object. 
    /// </summary> 
    /// <returns> 
    /// An error message indicating what is wrong with this object. The default is an empty string (""). 
    /// </returns> 
    public string Error => string.Empty; 

    /// <summary> 
    /// Gets the error message for the property with the given name. 
    /// </summary> 
    /// <returns> 
    /// The error message for the property. The default is an empty string (""). 
    /// </returns> 
    /// <param name="columnName">The name of the property whose error message to get. </param> 
    public string this[string columnName] 
    { 
     get 
     { 
      CollectErrors(); 
      return Errors.ContainsKey(columnName) ? Errors[columnName] : string.Empty; 
     } 
    } 

    #endregion 

    #region methods 

    /// <summary> 
    /// Override this method in derived types to initialize command logic. 
    /// </summary> 
    protected virtual void InitCommands() 
    { 
    } 

    /// <summary> 
    /// Can be overridden by derived types to react on the finisihing of error-collections. 
    /// </summary> 
    protected virtual void OnErrorsCollected() 
    { 
    } 

    /// <summary> 
    /// Raises the <see cref="PropertyChanged" /> event. 
    /// </summary> 
    /// <param name="propertyName">The name of the property which value has changed.</param> 
    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    /// <summary> 
    /// Is called by the indexer to collect all errors and not only the one for a special field. 
    /// </summary> 
    /// <remarks> 
    /// Because <see cref="HasErrors" /> depends on the <see cref="Errors" /> dictionary this 
    /// ensures that controls like buttons can switch their state accordingly. 
    /// </remarks> 
    private void CollectErrors() 
    { 
     Errors.Clear(); 
     PropertyInfos.ForEach(
      prop => 
      { 
       var currentValue = prop.GetValue(this); 
       var requiredAttr = prop.GetCustomAttribute<RequiredAttribute>(); 
       var maxLenAttr = prop.GetCustomAttribute<MaxLengthAttribute>(); 

       if (requiredAttr != null) 
       { 
        if (string.IsNullOrEmpty(currentValue?.ToString() ?? string.Empty)) 
        { 
         Errors.Add(prop.Name, requiredAttr.ErrorMessage); 
        } 
       } 
       if (maxLenAttr != null) 
       { 
        if ((currentValue?.ToString() ?? string.Empty).Length > maxLenAttr.Length) 
        { 
         Errors.Add(prop.Name, maxLenAttr.ErrorMessage); 
        } 
       } 


       // further attributes 
      }); 
     // we have to this because the Dictionary does not implement INotifyPropertyChanged    
     OnPropertyChanged(nameof(HasErrors)); 
     OnPropertyChanged(nameof(IsOk)); 
     // commands do not recognize property changes automatically 
     OnErrorsCollected(); 
    } 

    #endregion 

    #region properties 

    /// <summary> 
    /// Indicates whether this instance has any errors. 
    /// </summary> 
    public bool HasErrors => Errors.Any(); 

    /// <summary> 
    /// The opposite of <see cref="HasErrors" />. 
    /// </summary> 
    /// <remarks> 
    /// Exists for convenient binding only. 
    /// </remarks> 
    public bool IsOk => !HasErrors; 

    /// <summary> 
    /// Retrieves a list of all properties with attributes required for <see cref="IDataErrorInfo" /> automation. 
    /// </summary> 
    protected List<PropertyInfo> PropertyInfos 
    { 
     get 
     { 
      return _propertyInfos 
        ?? (_propertyInfos = 
         GetType() 
          .GetProperties(BindingFlags.Public | BindingFlags.Instance) 
          .Where(prop => prop.IsDefined(typeof(RequiredAttribute), true) || prop.IsDefined(typeof(MaxLengthAttribute), true)) 
          .ToList()); 
     } 
    } 

    /// <summary> 
    /// A dictionary of current errors with the name of the error-field as the key and the error 
    /// text as the value. 
    /// </summary> 
    private Dictionary<string, string> Errors { get; } = new Dictionary<string, string>(); 

    #endregion 
} 

}

どのように私は私のBasemodelクラスで正規表現の属性を追加することができますか?どんな助けもありがとう。ありがとう

答えて

1

moreまたは節を追加する代わりに - || - プロパティには、ValidationAttributeから派生したすべての属性を取得できます。すべてのDataAnnotation属性は、このクラスから派生されています

/// <summary> 
/// Retrieves a list of all properties with attributes required for <see cref="IDataErrorInfo" /> automation. 
/// </summary> 
protected List<PropertyInfo> PropertyInfos 
{ 
    get 
    { 
     return _propertyInfos 
       ?? (_propertyInfos = 
        GetType() 
         .GetProperties(BindingFlags.Public | BindingFlags.Instance) 
         .Where(prop => prop.IsDefined(typeof(ValidationAttribute), true)) 
         .ToList()); 
    } 
} 

あなたはあなたがして追加することができ、このアプローチが気に入らない場合は||各属性の種類によって句は、あなたが処理したい:

protected List<PropertyInfo> PropertyInfos 
{ 
    get 
    { 
     return _propertyInfos 
       ?? (_propertyInfos = 
        GetType() 
         .GetProperties(BindingFlags.Public | BindingFlags.Instance) 
         .Where(prop => 
          prop.IsDefined(typeof(RequiredAttribute), true) || 
          prop.IsDefined(typeof(MaxLengthAttribute), true) || 
          prop.IsDefined(typeof(RegularExpressionAttribute), true)) 
         .ToList()); 
    } 
} 

あなたのコメントを1として、私はあなたがかなりすぐに醜い取得します、あなたの属性や、あなたのCollectErrors方法を検証する一般的な方法が必要だと思います。

プリズムを使用して開発したプロジェクトからこのアプローチを試してみてください。このコードはあなたのBaseModelクラスに入るはずです。

private bool TryValidateProperty(PropertyInfo propertyInfo, List<string> propertyErrors) 
{ 
    var results = new List<ValidationResult>(); 
    var context = new ValidationContext(this) { MemberName = propertyInfo.Name }; 
    var propertyValue = propertyInfo.GetValue(this); 

    // Validate the property 
    var isValid = Validator.TryValidateProperty(propertyValue, context, results); 

    if (results.Any()) { propertyErrors.AddRange(results.Select(c => c.ErrorMessage)); } 

    return isValid; 
} 

/// <summary> 
/// Is called by the indexer to collect all errors and not only the one for a special field. 
/// </summary> 
/// <remarks> 
/// Because <see cref="HasErrors" /> depends on the <see cref="Errors" /> dictionary this 
/// ensures that controls like buttons can switch their state accordingly. 
/// </remarks> 
private void CollectErrors() 
{ 
    Errors.Clear(); 
    PropertyInfos.ForEach(
     prop => 
     { 
      //Validate generically 
      var errors = new List<string>(); 
      var isValid = TryValidateProperty(prop, errors); 
      if (!isValid) 
       //As you're using a dictionary to store the errors and the key is the name of the property, then add only the first error encountered. 
       Errors.Add(prop.Name, errors.First()); 
     }); 
    // we have to this because the Dictionary does not implement INotifyPropertyChanged    
    OnPropertyChanged(nameof(HasErrors)); 
    OnPropertyChanged(nameof(IsOk)); 
    // commands do not recognize property changes automatically 
    OnErrorsCollected(); 
} 
+0

はいますが、どのように私は私が必要とMAXLENGTH属性 –

+0

@AmadZafarの場合はやって正確に同じように、正規表現の場合には、エラーを収集します、私は私の答えを編集しました。私はそれがあなたを正しい道に導くことを願っています。それがあなたのためにどのように機能するか教えてください。 –

+0

エラーが定義された辞書であるError.AddRangeにエラーが発生します プライベートディクショナリエラー{get; } =新しい辞書<文字列、文字列>(); –

関連する問題