原文: WPF中使用Data Annotations驗證Model .NET Framework中System.ComponentModel.DataAnnotations提供了很多屬性來驗證對象的屬性。可以在C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\{.NET Version}\路徑下面找到System.ComponentModel.DataAnnotations.dll
public class User
{
[Required]
[StringLength(20)]
public string Name { get; set; }
[Range(1,120)]
public int Age { get; set; }
}
檢查一個執行個體是否合法有效,使用下面的代碼,具體可以參考:
https://msdn.microsoft.com/en-us/library/dd411772%28v=vs.110%29.aspxValidator.TryValidateObject(obj,new ValidationContext(obj),results,true);
static void Main(string[] args)
{
ICollection<ValidationResult> results = null;
User invalidUser = new User
{
Name = "My name is System.ComponentModel.DataAnnotations",
Age = -1,
};
if(!Validate(invalidUser, out results))
{
Console.WriteLine(string.Join("\n", results.Select(o=>o.ErrorMessage)));
}
else
{
Console.WriteLine("I am a valid object.");
}
Console.ReadKey();
}
static bool Validate<T>(T obj, out ICollection<ValidationResult> results)
{
results = new List<ValidationResult>();
return Validator.TryValidateObject(obj, new ValidationContext(obj), results, true);
}
代碼中執行個體化了一個非法的User,代碼執行結果如下:

這些ErrorMessage是.NET提供的,如果需要自定義錯誤資訊可以在Attribute上增加ErrorMessage,代碼如下:
public class User
{
[Required]
[StringLength(20, ErrorMessage ="Out of range~")]
public string Name { get; set; }
[Range(1,120, ErrorMessage ="Not a valid age.")]
public int Age { get; set; }
}
執行結果如下:
如果将User的屬性修改為合法的值,結果如下:
User validUser = new User
{
Name = "Hellen",
Age = 18,
};
在WPF中,繼承IDataErrorInfo接口,通過IDataErrorInfo來傳遞Data Annotation的ErrorMessage。
class PropertyValidateModel : IDataErrorInfo
{
public string this[string columnName]
{
get
{
List<ValidationResult> validationResults = new List<ValidationResult>();
bool result = Validator.TryValidateProperty(
GetType().GetProperty(columnName).GetValue(this),
new ValidationContext(this)
{
MemberName = columnName
},
validationResults);
if (result)
return null;
return validationResults.First().ErrorMessage;
}
}
public string Error
{
get
{
return null;
}
}
}
這裡隻驗證單個屬性,下面是Model類,注意:Model需要繼承INotifyPropertyChanged接口,直接看代碼,
class User : PropertyValidateModel, INotifyPropertyChanged
{
private string _name = string.Empty;
private int _age = 0;
[Required]
[StringLength(20)]
public string Name
{
get
{
return _name;
}
set
{
if(_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
[Required]
[Range(1,120)]
public int Age
{
get
{
return _age;
}
set
{
if(_age != value)
{
_age = value;
RaisePropertyChanged("Age");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
下面看一下UI這一塊的ErrorMessage綁定
<StackPanel>
<TextBlock Text="Name: "/>
<TextBox Text="{Binding User.Name,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Margin="0,10">
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="textBox" />
<TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
<TextBlock Text="Age" />
<TextBox Text="{Binding User.Age, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Margin="0,10">
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="textBox" />
<TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
</StackPanel>
運作結果如下:
補充一個内容:
如何自定義一個ValidationAttribute。隻需要繼承ValidationAttribute,并重寫IsValid方法即可。例如:
public class DivisibleBy7Attribute : ValidationAttribute
{
public DivisibleBy7Attribute()
:base("{0} value is not divisible by 7")
{
}
protected override ValidationResult IsValid(
object value,
ValidationContext validationContext)
{
decimal val = (decimal)value;
bool vaild = val % 7 == 0;
if (vaild)
return null;
return new ValidationResult(base.FormatErrorMessage(validationContext.MemberName));
}
}
感謝您的閱讀!代碼點選
這裡下載下傳。