我正在创建一个WPF应用程序,它将使用我的业务对象实现的IDataErrorInfo
数据验证。我一直在与this demo from a blog post合作,以了解ValidatesOnDataErrors
。
该演示是一个简单的应用程序,它将几个文本框绑定到Contact对象,并使用数据绑定中的IDataErrorInfo
实现ValidatesOnDataErrors=True
验证。要有效,文本框必须至少包含五个字符。
这是我的问题:在演示中,只要文本框失去焦点,就会触发验证。实际上,文本框在应用程序启动时初始化为无效状态(红色边框)。我的应用程序必须推迟验证,直到用户单击“确定”按钮提交页面。此时,如果文本框无效,则应验证文本框并将其置于错误状态。
那么,在用户单击“确定”按钮之前,我将如何推迟对文本框的验证?谢谢你的帮助。
答案 0 :(得分:7)
感谢迈克尔的帮助。不幸的是,我需要绑定以保持不断同步,只有延迟验证。否则,迈克尔的解决方案就能胜任。所以,我的方向略有不同。这是我最终实施的解决方案。
简单演示:让我们从最简单的案例开始:我的业务对象实现IDataErrorInfo
;我们假设我可以修改它的实现方式。我给每个业务对象一个额外的布尔属性ValidationEnabled
,并修改IDataErrorInfo
实现,以便在该属性为false时始终返回null结果。
我在原帖中提到的演示使用了一个带有两个属性的Contact对象; FirstName和LastName。我添加了一个ValidationEnabled属性并修改了IDataErrorInfo
实现,如下所示:
#region IDataErrorInfo Members
public string Error
{
get { throw new System.NotImplementedException(); }
}
public string this[string columnName]
{
get
{
// Initialize
string result = null;
// Perform validation only if enabled
if (ValidationEnabled)
{
switch (columnName)
{
// Validate 'First Name'
case "FirstName":
if (string.IsNullOrEmpty(FirstName))
{
result = "First name has to be set";
}
else if(FirstName.Length < 5)
{
result = "First name must be at least five characters";
}
break;
// Validate "Last Name"
case "LastName":
if (string.IsNullOrEmpty(LastName))
{
result = "Last name has to be set";
}
else if (LastName.Length < 5)
{
result = "Last name must be at least five characters";
}
break;
}
}
// Set return value
return result;
}
}
#endregion
在我的简单演示版本中,我将“提交”按钮连接到代码隐藏中的事件处理程序,该处理程序启用验证并刷新两个文本框的绑定:
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var contact = (Contact) DataContext;
contact.ValidationEnabled = true;
var binding = FirstNameBox.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
binding = LastNameBox.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
}
现在,在我尝试提交表单之前,红色轮廓不会出现。
真实世界:在我的制作应用中,我无法控制业务对象,也无法像我在简单演示中那样修改它们。因此,我为业务对象创建了一个简单的传递包装器,它将要数据绑定的属性公开给视图,并将这些属性链接到包装的业务对象的相应属性。包装器实现IDataErrorInfo并包含ValidationEnabled
属性。
如果未启用验证,则包装器的IDataErrorInfo实现始终返回null。如果启用了验证,那么包装器会在包装对象上调用IDataErrorInfo实现并返回从那里获取的内容。
使用Model-View-ViewModel模式的任何人都会熟悉这种方法。我们正在做的是为业务对象创建一个视图模型包装器,许多开发人员认为它是MVVM的最佳实践。它将业务模型问题(简单对象验证)中的UI问题(压缩红色边框直到提交页面)分开。
此外,我的生产应用程序不会在代码隐藏中使用事件处理程序。根据MVVM,该按钮将连接到ICommand,它将包含简单演示中OnButtonClick()处理程序的逻辑。
我希望这有助于其他人在未来研究这个问题。
答案 1 :(得分:0)
数据绑定具有UpdateSourceTrigger属性。顾名思义,它指定何时更新绑定源。对于Text属性,默认情况下设置为LostFocus。您可以将其设置为Explicit并在代码中调用BindingExpression的UpdateSource方法。另一方面,您也可以推迟提升PropertyChanged事件。但是,我认为这些并不能解决应用程序启动时的验证问题。希望这会有所帮助。