如何显示 DataAnnotations 的错误消息
How to display the error message for DataAnnotations
我花了大约一个小时的时间在谷歌上搜索这个问题的答案,但几乎每个结果都在 ASP.NET 或谈论对我无用的 Code First 方法。
我基本上得到了数据库优先 entity framework POCO 对象,我正在为使用 IDataErrorInfo 提供验证。
现在这工作正常,除了我有一个 200 行长的索引器,其中包含大约 40 个 if 语句。 (我是认真的。)
我现在正在做的是像这样扩展 类:
public partial class MyPocoObject : IDataErrorInfo
{
public string Error
{
get { throw new NotImplementedException("IDataErrorInfo.Error"); }
}
public string this[string columnName]
{
get
{
string result = null;
// There's about 40 if statements here...
}
}
}
显然,这是错误的,所以我正在尝试改用 DataAnnotations。
这是我目前所了解的。
我创建元数据 类 是这样的:
[MetadataType(typeof(MyObjectMetaData))]
public partial class MyObject { }
public class MyObjectMetaData
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
public string Forename;
}
然后我将控件声明为:
<TextBox Text="{Binding SelectedObject.Forename, NotifyOnValidationError=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
那么我在别处有触发器:
<Style TargetType="TextBox" BasedOn="{StaticResource Global}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
当我使用 IDataErrorInfo 执行此操作时,当验证失败时,我会得到一个红色边框和一个带有错误消息的工具提示。使用数据注释我一无所获。
我应该如何实施?因为一个方法中有 40 个 if 语句是疯狂的。
更新:
我已经尝试了答案中建议的代码,但它不起作用,尽管我认为我做错了。
public partial class Member : IDataErrorInfo
{
// Error: The type 'Project.Client.Models.Member' already contains a definition for 'Forename'
[Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
public string Forename;
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public string Error
{
get { throw new NotImplementedException("IDataErrorInfo.Error"); }
}
public string this[string columnName]
{
get { return OnValidate(columnName); }
}
protected virtual string OnValidate(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
string error = string.Empty;
// Error: Project.Client.Models.Member.GetValue<T>(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly
var value = GetValue(propertyName);
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
protected T GetValue<T>(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
object value;
if (!_values.TryGetValue(propertyName, out value))
{
value = default(T);
_values.Add(propertyName, value);
}
return (T)value;
}
}
更新二:
MVVM 文章中链接的代码似乎有效,但即使 OnValidate 正在触发,也没有显示任何错误消息。
尽管现在还有其他问题...即使文本框的内容发生变化,从 GetValue 返回的值始终相同,并且在未从我的数据库加载的空对象上,验证不会触发完全没有。
一些 .NET 技术可以检索和处理元数据类型,而另一些则不能。
使用前尝试注册好友class:
var myObjectMetadaProviderProvider = new
AssociatedMetadataTypeTypeDescriptionProvider(
typeof(MyObject),
typeof(MyObjectMetaData));
TypeDescriptor.AddProvider(myObjectMetadaProviderProvider , typeof(MyObject));
这允许以透明的方式检索在好友 classes 中声明的属性,而无需了解主 class.
中的元数据类型
看来您必须手动集成DataAnnotations 验证。也许 System.ComponentModel.DataAnnotations.Validator 默认情况下不使用 MetadataType,但像我之前的回答一样在 TypeDescriptor 中注册它应该可以。
我的意思是你必须实现你的验证方法并使用System.ComponentModel.DataAnnotations.Validator。
在我链接的源代码的PropertyChangedNotification实现中抢劫:
/// <summary>
/// Validates current instance properties using Data Annotations.
/// </summary>
/// <param name="propertyName">This instance property to validate.</param>
/// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
protected virtual string OnValidate(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
string error = string.Empty;
var value = GetValue(propertyName);
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
我自己解决了这个问题,方法是绑定到视图模型中的 属性 而不是模型本身,并将注释添加到视图模型,而不是试图扩展和弄乱模型。
想想看,应该是我先做的....
我花了大约一个小时的时间在谷歌上搜索这个问题的答案,但几乎每个结果都在 ASP.NET 或谈论对我无用的 Code First 方法。
我基本上得到了数据库优先 entity framework POCO 对象,我正在为使用 IDataErrorInfo 提供验证。
现在这工作正常,除了我有一个 200 行长的索引器,其中包含大约 40 个 if 语句。 (我是认真的。)
我现在正在做的是像这样扩展 类:
public partial class MyPocoObject : IDataErrorInfo
{
public string Error
{
get { throw new NotImplementedException("IDataErrorInfo.Error"); }
}
public string this[string columnName]
{
get
{
string result = null;
// There's about 40 if statements here...
}
}
}
显然,这是错误的,所以我正在尝试改用 DataAnnotations。
这是我目前所了解的。
我创建元数据 类 是这样的:
[MetadataType(typeof(MyObjectMetaData))]
public partial class MyObject { }
public class MyObjectMetaData
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
public string Forename;
}
然后我将控件声明为:
<TextBox Text="{Binding SelectedObject.Forename, NotifyOnValidationError=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
那么我在别处有触发器:
<Style TargetType="TextBox" BasedOn="{StaticResource Global}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
当我使用 IDataErrorInfo 执行此操作时,当验证失败时,我会得到一个红色边框和一个带有错误消息的工具提示。使用数据注释我一无所获。
我应该如何实施?因为一个方法中有 40 个 if 语句是疯狂的。
更新: 我已经尝试了答案中建议的代码,但它不起作用,尽管我认为我做错了。
public partial class Member : IDataErrorInfo
{
// Error: The type 'Project.Client.Models.Member' already contains a definition for 'Forename'
[Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
public string Forename;
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public string Error
{
get { throw new NotImplementedException("IDataErrorInfo.Error"); }
}
public string this[string columnName]
{
get { return OnValidate(columnName); }
}
protected virtual string OnValidate(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
string error = string.Empty;
// Error: Project.Client.Models.Member.GetValue<T>(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly
var value = GetValue(propertyName);
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
protected T GetValue<T>(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
object value;
if (!_values.TryGetValue(propertyName, out value))
{
value = default(T);
_values.Add(propertyName, value);
}
return (T)value;
}
}
更新二: MVVM 文章中链接的代码似乎有效,但即使 OnValidate 正在触发,也没有显示任何错误消息。
尽管现在还有其他问题...即使文本框的内容发生变化,从 GetValue 返回的值始终相同,并且在未从我的数据库加载的空对象上,验证不会触发完全没有。
一些 .NET 技术可以检索和处理元数据类型,而另一些则不能。
使用前尝试注册好友class:
var myObjectMetadaProviderProvider = new
AssociatedMetadataTypeTypeDescriptionProvider(
typeof(MyObject),
typeof(MyObjectMetaData));
TypeDescriptor.AddProvider(myObjectMetadaProviderProvider , typeof(MyObject));
这允许以透明的方式检索在好友 classes 中声明的属性,而无需了解主 class.
中的元数据类型看来您必须手动集成DataAnnotations 验证。也许 System.ComponentModel.DataAnnotations.Validator 默认情况下不使用 MetadataType,但像我之前的回答一样在 TypeDescriptor 中注册它应该可以。
我的意思是你必须实现你的验证方法并使用System.ComponentModel.DataAnnotations.Validator。
在我链接的源代码的PropertyChangedNotification实现中抢劫:
/// <summary>
/// Validates current instance properties using Data Annotations.
/// </summary>
/// <param name="propertyName">This instance property to validate.</param>
/// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
protected virtual string OnValidate(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
string error = string.Empty;
var value = GetValue(propertyName);
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
我自己解决了这个问题,方法是绑定到视图模型中的 属性 而不是模型本身,并将注释添加到视图模型,而不是试图扩展和弄乱模型。
想想看,应该是我先做的....