MVVM - 验证

man*_*nni 16 c# validation business-logic mvvm

我们试图在mvvm中弄清楚在业务逻辑或模型中进行验证的验证.我在业务逻辑中实现了异常类型的验证 - 可以在这里找到简化的图表: 替代文字

如果我们有很多输入彼此独立,那么没有问题,抛出异常,文本框会捕获一个标记,它为每个错误的输入设置了红色边框.但是,当我们有依赖值时,我们就遇到了麻烦.例如

  • 模型中的Value1和Value2必须不一样,所以我们在每个寻找equals值的函数中都有一个validate函数,如果发生这种情况则抛出异常

  • 现在,如果我们将Value1设置为0而将Value2设置为1,一切都很好

  • Value1在GUI中设置为1 - >这个被标记为红色,因为未触发其他值的验证,因此GUI中的Value2未标记为错误

  • 在GUI中将Value2设置为2,现在我们已达到有效状态,但只有Value2得到验证,因此Value1仍被标记为有错

有没有一个共同的模式来解决这个问题?我们不希望在两个文本框之间的GUI中引入依赖关系,因为此逻辑应仅存在于业务逻辑层中.

除了通过异常实现验证之外,还可以实现IDataErrorInfo接口,但问题仍然存在,没有办法强制依赖值再次验证它们的值,至少没有我能看到:)

任何帮助表示赞赏

欢呼,曼尼


[清理,删除不必要的步骤]


15.11.2010 - 第2部分

好的,在这里重新思考,我们将继续使用businesslogic层.这是我们当前计划的配置: 替代文字 (图像在这里缩小了一点,请在单独的窗口打开它以完整尺寸显示)一切都或多或少清晰,除了如果数据模型如何通知不同编辑器的所有视图模型/模型克隆在业务逻辑下变了.一种方法是跟踪创建它们的业务逻辑中的克隆模型.使用业务逻辑commit()更改数据模型时,可以向所有其他已注册的模型克隆通知更改并进一步传播它们.或者,业务逻辑可以发布所有视图模型订阅的事件,以便他们也能获得更改 - 任何人都可以给我一个提示更好的提示吗?

再次感谢您的帮助,抱歉,我是如此精神错乱;)

slu*_*ter 15

您可以考虑使用System.ComponentModel.IDataErrorInfo接口.这个非常方便的界面使您能够:

  • 以符合MVVM的方式进行验证
  • 为任何特定字段执行自定义验证(如果需要,验证可以检查多个值)
  • 将UI绑定到验证错误

您在viewmodel上实现IDataErrorInfo(甚至在视图模型库中实际虚拟,并在派生视图模型中覆盖它).由于数据绑定的性质,我需要检查的值都在视图模型中,我可以测试它们的任何组合.当然,您仍然在业务层中进行验证,但您不再需要前往业务层(或模型)来进行某些验证.

以下是来自(WPF)屏幕的快速示例,该屏幕收集了一些用户详细信息并对其进行了基本验证:

C#代码:

    #region IDataErrorInfo Members

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <value></value>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    public override string Error
    {
        get
        {
            return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"];
        }
    }

    /// <summary>
    /// Gets the <see cref="System.String"/> with the specified column name.
    /// </summary>
    /// <value></value>
    public override string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case "UserCode":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20)
                        return "User Code must be less than or equal to 20 characters";
                    break;

                case "UserName":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60)
                        return "User Name must be less than or equal to 60 characters";
                    break;

                case "Password":
                    if (!string.IsNullOrEmpty(Password) && Password.Length > 60)
                        return "Password must be less than or equal to 60 characters";
                    break;

                case "ConfirmedPassword":
                    if (Password != ConfirmedPassword)
                        return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch; 
                    break;

                case "EmailAddress":
                    if (!string.IsNullOrEmpty(EmailAddress))
                    {
                        var r = new Regex(_emailRegex);
                        if (!r.IsMatch(EmailAddress))
                            return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat;
                    }
                    break;
            }
            return string.Empty;
        }
    }

    #endregion
Run Code Online (Sandbox Code Playgroud)

这是页面上两个文本框的XAML标记(特别注意绑定中的ValidatesOnDataErrorsValidatesOnExceptions属性Text):

<TextBox Name="UserCodeTextBox" 
         Text="{Binding UserCode, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,0,150,0"  
         CharacterCasing="Upper"
         />

<TextBox Name="UserNameTextBox" 
         Text="{Binding UserName, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,30,0,0"  
         />
Run Code Online (Sandbox Code Playgroud)

  • 我不喜欢在代码中没有多少字符串,如果我每次重命名一个属性,感觉它会在运行时中断 (2认同)