【问题标题】:IDataErrorInfo: Validating when page submittedIDataErrorInfo:验证页面何时提交
【发布时间】:2010-04-07 10:25:42
【问题描述】:

我正在创建一个 WPF 应用程序,它将使用我的业务对象实现的 IDataErrorInfo 数据验证。我一直在与this demo from a blog post 合作以了解ValidatesOnDataErrors

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

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

那么,在用户单击“确定”按钮之前,我将如何推迟对文本框的验证?感谢您的帮助。

【问题讨论】:

    标签: wpf validation idataerrorinfo


    【解决方案1】:

    感谢迈克尔的帮助。不幸的是,我需要绑定保持不断同步,只有延迟验证。否则,迈克尔的解决方案就可以完成这项工作。所以,我走向了一个稍微不同的方向。这是我最终实施的解决方案。

    简单演示:让我们从最简单的案例开始:我的业务对象实现IDataErrorInfo;假设我可以修改它的实现方式。我给每个业务对象一个额外的布尔属性ValidationEnabled,然后我修改IDataErrorInfo 实现以在该属性为假时始终返回空结果。

    我在原帖中提到的演示使用了一个具有两个属性的联系人对象;名字和姓氏。我添加了一个 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() 处理程序的逻辑。

    我希望这对其他研究此问题的人有所帮助。

    【讨论】:

      【解决方案2】:

      数据绑定有一个 UpdateSourceTrigger 属性。顾名思义,它指定何时更新绑定源。对于 Text 属性,默认设置为 LostFocus。您可以将其设置为 Explicit 并在代码中调用 BindingExpression 的 UpdateSource 方法。另一方面,您也可以推迟引发 PropertyChanged 事件。但是,我认为这些不会解决应用程序启动时的验证问题。希望这会有所帮助。

      【讨论】:

      • 这是部分解决方案——我的数据绑定在我提交之前不会更新。但是,我感谢您的帮助,因此我接受了它。我在下面详细介绍了一个更复杂的解决方案,它可以保持绑定同步但将验证推迟到页面提交。
      猜你喜欢
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 2020-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      相关资源
      最近更新 更多