2011-12-13 105 views
0

我有一個數據網格,它綁定到實現INotifyPropertyChanged的Item對象。MVVM Datagrid從視圖和模型更新

在ViewModel中,我訂閱了來自更新Item對象的外部設備服務的更改。 datagrid是可編輯的,因此Item也可以從View中更改。該值應寫入設備,但尚未在視圖中更新,因爲設備寫入可能會失敗。如果成功,設備將發出一個我已經訂閱的事件。

我的一些擔憂是。

我在哪裏可以通過ViewModel或Item對象在設備服務上調用寫入? 如何確保數據網格中顯示的值在編輯後「恢復」,直到從設備接收事件?

的幾點思考

  1. 如果它的項目對象,然後Item對象不再是DTO,而是一個ViewModel我猜。所以我會爲同一視圖(用戶控件)提供兩種視圖模型。一個用於用戶控件,另一個用於數據網格中的項目。這不符合我對視圖模型的理解。但也許這是錯的? 然後Item如何知道值是從視圖(由用戶)還是由視圖模型(由設備服務)更新?

  2. ViewModel訂閱Item對象上的PropertyChanged。要檢測值是否從視圖中更改,ViewModel可以從服務中取消訂閱PropertyChanged或設置標誌。它似乎很笨重,但會起作用。 也許我應該做兩個屬性:ViewValue和ServiceValue。 ViewModel應該更新ServiceValue並訂閱ViewValue,它可以在閱讀ViewValue之後將ViewValue還原爲ServiceValue。

  3. 視圖處理CellEditEnding並通知視圖模型

回答

2

關於1點):是的,使用視圖模型綁定對UI,而不是DTO。 這是幫助從MVVM中的視圖中分離數據的主要思想。

至於點2)和3),我建議你在你的ViewModels上實現IEditableObject接口,可能在一個公共基類上。

該界面提供了方法BeginEdit(), CancelEdit(), and EndEdit()。通過使用這些方法,您可以清楚而可讀地控制何時修改哪個對象以及何時提交這些更改,例如到服務或數據庫。

此外,實現這些方法可以爲您提供一種機制來處理像「ViewValue」和「ServiceValue」這樣的不同數據版本。當調用方法BeginEdit()時,可以創建ServiceValue的本地副本作爲回退,如果調用方法CancelEdit(),則調用此本地回退值。如果調用EndEdit(),那麼這是將值提交回服務的時間,並且在成功之後將當前值存儲在該本地臨時值中作爲新的回退值。

編輯以添加點1回答)

我不知道這是否是「最佳實踐」,但至少這是我們在工作中會英寸

我們通常以這樣一種方式組織ViewModel,即每個視圖都有一個ViewModel,它包含特定視圖的所有信息。我們稱之爲「主ViewModel」。如果我們需要一個視圖層次結構,我們將實現遵循相同層次結構的ViewModel層次結構。

在像您這樣的情況下,我們會將DataGrid放入另一個包含在主視圖中的UserControl。主ViewModel將保存另一個ViewModel,它再次保存DataGrid所需的數據。這個ViewModel將被設置爲DataGrid-UserControl的DataContext。這樣你仍然保持一個乾淨的one-ViewModel-per-View分離。

然後可以配置DataGrid中的數據的其他格式,數值爲Templates

+0

IEditableObject聽起來不錯,我會看看它。關於第1點,也許我還不夠清楚。我擔心的是,對於「相同」視圖,我可能有兩個視圖模型,一個用於窗口,另一個用於窗口中數據網格的項目。我在想一個viewmodel屬於一個window/usercontrol,而不是一個數據網格中的項目。但也許我的想法是錯誤的? – Karsten

+0

您也可以實現'你們哪綁定到'DataGrid'實體名單IEditableObject'接口。它會給你更多的靈活性。 –

+0

Hmm interresting將DataGrid放入用戶控件中。我喜歡清晰的名字,所以我想知道你是如何命名用戶控件和視圖模型的? – Karsten

1

1)讓您的DTO類由您的外部數據服務更新將不會進入視圖模型。您的DTO是您的模型或業務對象層的一部分。它的工作是在演示文稿(視圖和視圖模型)和存儲層(數據庫)之間傳輸數據,並執行驗證(如果需要)。由外部(非視圖)服務進行更新是其職責範圍內的內容。你對每個窗口或者用戶控件的一個虛擬機的評論是沒有錯的 - 虛擬機是在每個視圖上而不是按照控制的基礎上分配的(儘管可以爲多個視圖重用相同的虛擬機類)。您應該擁有視圖在VM上綁定的DTO實例。這是虛擬機的工作 - 組織,管理並向視圖呈現模型的必需部分。

爲了讓DTO知道更新來自哪裏,就像您在問題中提到的一樣,您可以添加一個標誌來指示它是來自視圖還是服務,並根據需要進行設置。或者,您可以使服務通過公共方法更新DTO,並讓視圖直接綁定到屬性。根據你的設計,這個選項可能比設置一個標誌更不可行。

2)IEditableObject,正如在其他答案中提到的那樣,是一個不錯的選擇。在DTO上備份服務和視圖數據是不必要的,並且可以有效地將對象的大小增加三倍(假設它是一個很薄的包裝器,如果它是DTO,它應該是這樣)。如果你需要恢復到任一版本的數據的能力 - 比如說,因爲你給了用戶選擇恢復時使用哪個版本的選項 - 將額外的數據保留在虛擬機上而不是模型上。我想不出有什麼理由需要不涉及某種形式的演示或用戶交互決策的選項。數據驅動的還原應該始終是確定性的。

3)再次,IEditableObject。該觀點不應該通知視圖模型;它應該是無知的虛擬機(沒有任何引用)。這將放鬆兩層之間的耦合並增加應用程序的靈活性。我通常通過擁有專門處理視圖的控制器類來實現這一點。當它打開一個視圖時,它會創建一個新的VM實例,並將視圖的點號DataContext指向它。