2013-02-26 66 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'的'輸入區域',其中用戶通過使用圖形來輔助。