2013-02-26 61 views
1

所以我对MVVM相当陌生,我一直在关于用户输入验证的一些问题上挣扎。 WPF有一些内置的功能,似乎像“魔术”一样工作,并且通常我知道“魔术”不好。WPF的“好”特性真的很棒吗?还是他们太控制?

例如:如果绑定TextBox到具有类型的double和用户输入的“hello”成TextBox一个属性,WPF自动显示TextBox围绕红色边框通知该输入的用户无效。

这一切都很好,但它确实看起来像“魔法”。一位经验丰富的开发人员告诉我,WPF和类似的应用程序构建者想要控制太多。他表示,在Web开发中,View不知道该属性是什么类型。这对我有意义。所以这导致我的一般问题 - 应该WPF视图了解属性类型? - 如果我将Property属性声明为string,那么我可以通过视图对完成控制。而不是必须解决WPF的“聪明”TextBox“魔术”。

另一种表达我的问题的方式是 - 应该在Model或ViewModel中声明属性类型吗?

我明白,如果你在型号为double,并为string在视图模型申报物业类型必须在模型中分析。在我看过的MVVM应用程序的大多数示例中,Property类型在整个应用程序中都是相似的,但我认为不理解它使用的“愚蠢”视图会好很多。

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

+6

当您将一个'TextBox'绑定到double并键入像“hello”这样的字符串时,我认为实际发生的事情是WPF尝试将您的double值设置为字符串值,并引发异常。这种例外是导致红色边框出现在“TextBox”周围并显示错误消息,而不是任何特殊处理的原因。你可以轻易地在setter中为你的double属性抛出一个异常,并且会发生同样的事情。我不会真的称之为“魔术”,只是异常处理:) – Rachel 2013-02-26 14:34:10

+0

@Rachel我同意,但为什么不完全控制自己的输入?是的,当类型是“double”时,可以稍微控制它,但不如它是一个字符串。你可以创建一个几乎不可能破解的应用程序。我只是认为'View'应该是一种愚蠢的! – 2013-02-26 14:39:00

+0

我不知道为什么你会想要一个额外的图层。 WPF有两层:一个数据层和一个UI层。数据层应该代表你的数据。如果你有一个数字,它应该是一个数字数据类型,而不是一个字符串数据类型。用户界面层意味着为用户提供了一个友好的数据界面,因此您可以使用“文本框”来显示您的数字值,以便最终用户可以轻松编辑它。如果你强制你的数据层使用字符串而不是数字,因为你使用的是“TextBox”,那么你让UI控制你的应用程序,这不是WPF应该如何工作的。 – Rachel 2013-02-26 14:48:16

回答

5

是的,我认为WPF的该功能是“那该多好” :)

WPF有两个层次:数据层和用户界面层。

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

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

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

在问候你的具体的例子,当你绑定一个TextBox为双并键入像一个字符串“hello”,什么是真正发生的是,WPF尝试你的双值设置为一个字符串值,并抛出一个例外。

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

我不会真的称之为“神奇”,只是异常处理:)

但是为了避免随时抛出异常要验证输入,WPF提供IDataErrorInfo界面,你可以用它来验证财产没有抛出异常。用户界面将对这个界面引发的错误做出反应,这与对异常做出反应的方式相同。

+0

因此,你认为最好是简单地通知用户“TextBox”中的错误或阻止他们做出一个错误?我倾向于完全防止他们犯错误,而用您的解决方案,似乎并不可能。因为如果您只是抛出异常或通过错误信息通知用户,用户仍然需要做一些改变。我可以这么做,我只是觉得完全控制会更好,因为这会造成错误不可能发生的情况。我试图理解这个概念,所以只是和我一起。 – 2013-02-26 15:07:39

+0

@JordanCarroll重要的部分是你保持你的UI层和你的数据层分开。如果要防止用户在文本框中输入非数字字符,则可以在UI层中相当容易地完成此操作,例如将事件附加到OnTextInput上的OnKeyDown以防止在用户输入非数字数据。但是那种UI特定的验证应该在UI层中完成,而数据特定的验证(例如,数字不能低于0)应该发生在数据层中。 – Rachel 2013-02-26 15:10:54

+0

我同意这一点。但我还有另一个问题。因为'TextBox'希望输入是'double',所以它认为某些字符不重要,这使得验证变得困难。例如:如果我有一个'TextBox'绑定到一个'double',那么第一个小数点就被认为是不重要的。因此,在我试图验证文本的代码隐藏中,如果用户输入了“123.”,那么TextBox.Text属性烦恼地只返回“123”(不带“。”)。因此,在这种情况下,我无法完全控制用户输入。 – 2013-02-26 15:18:46

2

是的,应该的。

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

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

WPF默认吞下结合的异常数据,但你可以在你的查看类上加载事件添加处理程序。

_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}" 

就是这样。

1

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

宣言连接到数据库

属性在模型中声明。您需要将模型转换为用户友好的属性,在ViewModel中声明。例如,我们有一个存储在数据库中的值(值A)。 valueA通过使用用户可用的两个输入域来计算(值B值C)。在这种情况下值a模型中的声明,但VALUEBvalueC在你的视图模型只是声明,因为它们不需要被存储在数据库中做。 (技术上三者都是在您的视图模型可用,但只有值a模型中的声明)

我的理解是:

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