1

所以我对 MVVM 还是很陌生,我一直在努力解决一些关于用户输入验证的问题。WPF 有一些看起来像“魔术”的内置功能,一般来说,我知道“魔术”不好。

例如:如果您将 a 绑定TextBox到具有类型 of 的 Propertydouble并且用户在其中输入“hello” ,WPF 会自动在通知用户输入无效的TextBox周围显示一个红色边框。TextBox

这一切都很好,但看起来确实像“魔术”。一位经验丰富的开发人员告诉我,类似的 WPF 和应用程序构建器希望拥有过多的控制权。他说,在 Web 开发中,视图不会知道属性是什么类型。这对我来说很有意义。所以这引出了我的一般性问题——WPF 视图应该理解属性类型吗?- 如果我将 Property 类型声明为 a string,那么我可以完全控制视图。而不必解决 WPF 的“智能” TextBox“魔法”。

表达我的问题的另一种方法是 -应该在模型或视图模型中声明属性类型吗?

我了解,如果您将模型中的属性类型声明为 adoublestring在 ViewModel 中声明为 a ,则必须在模型中对其进行解析。在我看过的大多数 MVVM 应用程序示例中,Property 类型在整个应用程序中都是相似的,但我认为不了解它正在使用什么的“愚蠢”视图会好得多。

回到我的例子:如果 Property 被声明为 a String,您可以完全控制输入所需的格式并防止无效输入。这似乎是比信任 WPF 更好的解决方案TextBox

4

3 回答 3

5

是的,我认为 WPF 的特性是“很好” :)

WPF 有两层:数据层和 UI 层。

数据层包含您的数据。如果数据中有数字,它应该是数字数据类型,而不是字符串数据类型。

UI 层 (XAML) 仅旨在为数据提供用户友好的界面,以便用户可以轻松地与数据层进行交互。例如,如果您有一个包含数值的数据层,并且您希望用户能够编辑该值,您可以选择使用TextBox.

如果仅仅因为 UI 层使用 aTextBox来显示数据而强制数据层使用字符串而不是数字,那么您就是让 UI 控制您的应用程序,这不是 WPF 应该如何工作的。此外,像这样将两层混合在一起会使以后的维护变得更加困难。例如,如果您决定将 更改TextBoxNumericUpDownUI 控件会发生什么?现在你必须去修改你的数据层来改变 UI。

关于您的特定示例,当您将 a 绑定TextBox到双精度并键入“hello”之类的字符串时,实际发生的是 WPF 尝试将您的双精度值设置为字符串值,并引发异常。

该异常是导致红色边框出现在 周围TextBox并显示错误消息的原因,而不是任何特殊处理。你可以很容易地在你的 double 属性的 setter 中抛出一个异常,同样的事情也会发生。

我不会真正称其为“魔术”,只是异常处理:)

但是为了避免在您想要验证输入的任何时候抛出异常,WPF 提供了IDataErrorInfo接口,您可以使用它来验证您的属性而不会抛出异常。UI 将对使用此接口引发的错误做出反应,就像对异常做出反应一样。

于 2013-02-26T14:58:08.960 回答
2

是的,它应该。

Karl Shifflett 有一篇很棒的文章。输入验证 – UI 异常和模型验证错误

解决方案是检测无效输入。当用户输入无效的数据类型时,数据绑定管道将抛出异常。当它发生时,在View上处理它,然后在ViewModel上添加错误消息,以便您可以在需要时使用它。

WPF 默认情况下会吞下该数据绑定异常,但您可以在View类中的Loaded事件上添加一个处理程序。

_errorEventRoutedEventHandler = new RoutedEventHandler(ExceptionValidationErrorHandler);
this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, _errorEventRoutedEventHandler, true);

实现处理程序

private void ExceptionValidationErrorHandler(object sender, RoutedEventArgs e)
{
    // Add logic to handle this invalid data type exception. 
    // Add error messages to viewmodel, show notification dialog, etc
    ...
}

将 XAML 绑定NotifyOnValidationErrorValidatesOnDataErrorsValidatesOnExceptions上的这些属性设置为 true。

Text="{Binding UnitPrice, StringFormat=c, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"

就是这样。

于 2013-02-26T14:50:01.320 回答
1

由于您使用的是强类型语言,因此迟早需要验证。我不确定通过不使用现有的验证形式您想要实现什么。不要忘记,当给出无效输入时,您可以修改视图以执行您想要的任何操作。如果您不希望抛出任何异常(如@Rachel 所述),则使用字符串属性可能会阻止它们。

宣言

连接到数据库的属性在模型中声明。您需要将模型转换为用户友好的属性,在 ViewModel 中声明。例如,我们有一个存储在数据库中的值 ( valueA )。valueA是通过使用用户可用的两个输入字段(valueBvalueC)来计算的。在这种情况下valueA在您的模型中声明,但valueBvalueC仅在您的 ViewModel 中声明,因为它们不需要存储在数据库中。(从技术上讲,这三个都可以在您的 ViewModel 中使用,但您的模型中只声明了valueA

我理解的方式:

  • 模型具有存储在数据库中的属性
  • ViewModel将模型转换为用户可以处理的东西(反之亦然)。
  • View或多或少是“您的 ViewModel 的输入区域”,用户可以在其中通过使用图形获得帮助。
于 2013-02-26T14:55:11.637 回答