IDataErrorInfo:验证页面提交时间

Dav*_*man 4 validation wpf idataerrorinfo

我正在创建一个WPF应用程序,它将使用IDataErrorInfo我的业务对象实现的数据验证.我一直在博客文章中使用这个演示来理解ValidatesOnDataErrors.

该演示是一个简单的应用程序,它将几个文本框绑定到Contact对象IDataErrorInfo,并ValidatesOnDataErrors=True在数据绑定中实现验证.要有效,文本框必须至少包含五个字符.

这是我的问题:在演示中,只要文本框失去焦点,就会触发验证.实际上,文本框在应用程序启动时初始化为无效状态(红色边框).我的应用程序必须推迟验证,直到用户单击"确定"按钮提交页面.那时,文本框应该被验证并且如果无效则进入错误状态.

那么,在用户单击"确定"按钮之前,如何在文本框上推迟验证?谢谢你的帮助.

Dav*_*man 7

感谢Michael的帮助.不幸的是,我需要绑定以保持不断同步,只有延迟验证.否则,迈克尔的解决方案就能胜任.所以,我的方向略有不同.这是我最终实施的解决方案.

简单演示:让我们从最简单的案例开始:我的业务对象实现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
Run Code Online (Sandbox Code Playgroud)

在我的简单演示版本中,我将Submit按钮连接到代码隐藏中的事件处理程序,该处理程序启用验证并刷新两个文本框的绑定:

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();
}
Run Code Online (Sandbox Code Playgroud)

现在,在我尝试提交表单之前,红色轮廓不会出现.

现实世界:在我的生产应用程序中,我不控制业务对象,我无法像在简单演示中那样修改它们.因此,我为业务对象创建了一个简单的传递包装器,它将要数据绑定的属性公开给视图,并将这些属性链接到包装的业务对象的相应属性.包装器实现IDataErrorInfo并包含该ValidationEnabled属性.

如果未启用验证,则包装器的IDataErrorInfo实现始终返回null.如果启用了验证,那么包装器会在包装对象上调用IDataErrorInfo实现并返回从那里获取的内容.

使用Model-View-ViewModel模式的任何人都会熟悉这种方法.我们正在做的是为业务对象创建一个视图模型包装器,许多开发人员认为它是MVVM的最佳实践.它将业务模型关注点(简单对象验证)分离UI关注点(压缩红色边框直到提交页面).

此外,我的生产应用程序不会在代码隐藏中使用事件处理程序.根据MVVM,该按钮将连接到ICommand,它将包含简单演示中OnButtonClick()处理程序的逻辑.

我希望这对其他任何研究这个问题的人都有帮助.