WPF的“漂亮”功能真的很棒吗?还是他们太控制了?

时间:2013-02-26 14:01:44

标签: wpf mvvm

所以我对MVVM很新,我一直在努力解决有关用户输入验证的一些问题。 WPF有一些内置功能似乎像“魔术”一样,一般来说,我知道“魔术”并不好。

例如:如果将TextBox绑定到类型为double的属性,并且用户在TextBox中输入“hello”, WPF会自动在TextBox周围显示一个红色边框,通知用户输入无效。

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

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

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

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

3 个答案:

答案 0 :(得分:5)

是的,我认为WPF的这个功能“非常好”:)

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

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

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

如果强制数据层使用字符串而不是数字只是因为UI层使用TextBox来显示数据,那么您是让UI控制您的应用程序,而不是WPF的方式应该管用。另外,将这两层混合在一起使得将来更难以维护。例如,如果您决定将TextBox更改为NumericUpDown UI控件,会发生什么?现在,您必须修改数据层以进行UI更改。

关于您的特定示例,当您将TextBox绑定到double并键入类似“hello”的字符串时,实际发生的是WPF尝试将您的double值设置为字符串值,并且抛出异常。

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

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

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

答案 1 :(得分:2)

是的,应该。

Karl Shifflett有一篇很棒的文章。 Input Validation – UI Exceptions & Model Validation Errors

解决方案是检测无效输入。当用户输入无效数据类型时,数据绑定管道将抛出异常。如果它在查看上处理,然后在 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绑定 NotifyOnValidationError ValidatesOnDataErrors ValidatesOnExceptions 设置为true。

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

就是这样。

答案 2 :(得分:1)

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

<强>声明

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

我理解它的方式:

  • 模型具有存储在数据库中的属性
  • ViewModel 将模型转换为用户可以处理的内容(反之亦然)。
  • 查看或多或少是ViewModel 的'输入区域',用户可以通过使用图形获得帮助。