所以我对MVVM很新,我一直在努力解决有关用户输入验证的一些问题。 WPF有一些内置功能似乎像“魔术”一样,一般来说,我知道“魔术”并不好。
例如:如果将TextBox
绑定到类型为double
的属性,并且用户在TextBox
中输入“hello”, WPF会自动在TextBox
周围显示一个红色边框,通知用户输入无效。
这一切都很好,但看起来确实像“神奇”。有经验的开发人员告诉我,类似的WPF和应用程序构建者想要有太多的控制权。他说,在Web开发中,View不知道Property属于什么类型。这对我来说很有意义。所以这引出了我的一般性问题 - WPF View应该了解属性类型吗? - 如果我将属性类型声明为string
我可以拥有在视图上完全控制。而不是必须解决WPF的“智能”TextBox
“魔术”。
另一种表达我的问题的方法是 - 是否应在模型或ViewModel中声明属性类型?
据我所知,如果您在ViewModel中将模型中的Property类型声明为double
和string
,则必须在模型中对其进行解析。在我看过的MVVM应用程序的大多数示例中,属性类型在整个应用程序中是相似的,但我认为不明白它正在使用的“哑”视图会好得多。
回到我的示例:如果将属性声明为String
,您可以完全控制输入所需的格式并防止无效输入。这似乎是比信任WPF TextBox
更好的解决方案。
答案 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 )
我理解它的方式: