当我第一次向用户显示我的屏幕时,在用户有机会填写任何表单字段之前,我宁愿没有显示所有必需字段的验证消息。我已将绑定UpdateSourceTrigger
设置为LostFocus
,但错误仍会在第一次显示控件时显示。有没有办法解决这个问题?
XAML:
<TextBox Text="{Binding Path=OpeningOdometer, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}" />
视图模型:
[Required(ErrorMessage = "Please enter the opening odometer.")]
[Range(0, Double.MaxValue, ErrorMessage = "Opening Odometer must be a positive number")]
public string OpeningOdometer
{
get { return _openingOdometer; }
set
{
_openingOdometer = value;
NotifyOfPropertyChange(() => OpeningOdometer);
}
}
// Implementation of IDataErrorInfo
public string this[string columnName]
{
get
{
// This uses the System.ComponentModel.DataAnnotations placed on
// the OpeningOdometer property to produce an error string
// if the value of the property is in violation of any of the
// annotated rules.
return _valHelper.GetErrorsForProperty(columnName, this);
}
}
答案 0 :(得分:8)
我没有将验证逻辑放在索引器中。这将控制验证的时间到视图。在您的方案中,视图会在询问属性的错误信息时触发验证。我不知道会发生什么情况,我打赌你也不会。
相反,我在其setter中放置了属性的验证逻辑(更准确地说,是对验证函数的调用)。我将错误消息存储在键入属性名称的字典中,并让索引器查找该属性的错误消息。
默认情况下,错误消息是最新的属性的当前值。每当视图更新属性并请求其新的错误信息时,它都会得到正确的答案。
但是你也可以对字典中的实际内容进行相当精细的控制。如果您希望UI中的属性显示为有效,只需在字典中清除其错误消息(并引发PropertyChanged
,以便UI知道获取新的错误消息)。或者,您可以在构造视图模型对象时设置属性的支持字段而不是属性本身,从而绕过验证。
答案 1 :(得分:2)
如果您努力发布相关代码/ XAML的片段,则可以获得更好的答案。这样可以更容易地重现并消除大部分的猜测。
尝试在验证规则上设置ValidatesOnTargetUpdated="False"
,看看是否有帮助。
答案 2 :(得分:2)
只是为了说明我是如何使用IDataErrorInfo
...
我在视图绑定属性的每个setter中调用了一个名为OnDataUpdated()
的新方法,例如:
private string username;
public string Username
{
get { return username; }
set
{
username = value;
OnDataUpdated();
}
}
private string password;
public string Password
{
get { return password; }
set
{
password = value;
OnDataUpdated();
}
}
然后在OnDataUpdated()
内标记私有字段布尔值为true
,表示数据第一次发生了变化(FormType
只是我的业务案例所必需的):
private void OnDataUpdated()
{
dataChanged = true;
// .. Any other universal RaisePropertyChanged() events you may want to call to get your UI into sync. Eg. RaisePropertyChanged(() => CanConfirm);
}
然后在我的IDataErrorInfo
索引器属性中,我执行以下操作(我将其拆分,因此可以手动调用'ValidForm()'以执行表单验证。
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Username")
{
// If other payment amounts have fully paid for balance, and cash amount has been entered, deny
if (!ValidForm(FormType.Step1, columnName))
result = "Please enter the username field.";
}
else if (columnName == "Password")
{
if (!ValidForm(FormType.Step1, columnName))
result = "Please enter the password field.";
}
return result;
}
}
/// <summary>
/// Test if valid form.
/// </summary>
/// <param name="formType">Specify which form we should validate.</param>
/// <param name="columnName">If ommitted, entire form will be validated.</param>
/// <returns></returns>
private bool ValidForm(FormType formType, string columnName = null)
{
// This field is used to denote when data has changed on the form.
// If data has changed, we know we can activate any form validation.
// We do not activate the form validation until after a user has typed
// something in at least.
if (!dataChanged) return true;
var errors = false;
if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Username") && string.IsNullOrEmpty(Username)))
errors = true;
if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Password") && string.IsNullOrEmpty(Password)))
errors = true;
return !errors;
}
工作得很漂亮。现在,我只在用户编辑表单后出现验证样式。
如果你想要一些额外的锦上添花,你可以在RaisePropertyChanged(() => CanConfirm);
方法的OnDataUpdated()
中发表评论并将其与相关属性的确认按钮IsEnabled={Binding CanConfirm}
绑定:
/// <summary>
/// Can the user confirm step 1?
/// </summary>
public bool CanConfirm
{
get { return ValidForm(FormType.Step1); }
}
并且只有在您的表单有效时才会启用您的按钮。 :)
享受!祝WPF的庞然大物好运。