我在最近的一個項目(WinForm)中遇到一個這樣的問題,下面對問題陳述:
某工資計算模組的介面很複雜,8個DataGrid分別和8個DataSet綁定,還有一大堆的TextBox關聯另外兩個DataSet裡面的資料。更新介面的某一地方的資料,其他資料來源相應的地方會變化。不談論對需求分析到設計的好壞,在這樣一個複雜的UI下面,處理資料同步問題令我好擔憂。在最近的測試過程中,發生莫名奇妙的錯誤,找不到錯誤源,簡直鬱悶至死!主要是在某些情況下,資料變得不同步了,根本經不起“猴子測試”(在介面上亂點),悲哀至此,下定決心把關鍵區段重寫。
在重寫過程中,我就發現了一個重要的問題:控制介面的邏輯和處理業務資料的邏輯應各自獨立,就算介面顯示資料有錯誤,但實際的資料仍是平衡的。
舉例:在DataGrid中,一個CellValue從10 -》100,差值(新值和舊值相減)是90。我們要根據這個差值去處理其他資料的同步。
首先,問題是我們如何取出這個差值,開始我的做法是:DataGrid提供一個事件:ValidatingEditor。這個事件在輸入的新值到寫入資料來源之前提供一個驗證,在這裡我們可以用EventArgs裡面的新值和當前的值進行比較,得出差值。如果差值符合要求(商務邏輯),則把這個差值更新到各個相應資料來源中去來保持資料同步。如果差值不符合要求,則提示錯誤資訊,並還原原值。咋一看,什麼問題也沒有,邏輯也清晰,大家也覺得是吧?
在測試過程中,問題就出現了,往往是輸入一個新值後,“其他資料來源”也同步了,但是回頭一看,舊值還是舊值,新值並沒有填充到“本資料來源”中去,why?找了很長時間,雖然我們最終找出問題出在控制項本身上面,但是如何從根本上杜絕這類問題的發生呢?
就上面這個例子來說,我們找差值去同步資料的時候,在是寫在ValidatingEditor這個事件上面的。如果在這個事件的處理過程中發生了一些我們異想不到的異常(可能是控制項本身引發的或者是我們自己引發的),就會造成資料出錯。所以進行了以下改造:
考慮到如果ValidatingEditor驗證成功,必然會引發一個CellValueChanged事件,這裡可以肯定資料來源是被改變的了。所以,在ValidatingEditor只負責資料驗證和提示錯誤資訊,驗證不成功CellValueChanged不會被引發,如果成功,在事件CellValueChanged得到差值去同步各個資料來源。注意:取差值時,盡量不要擷取控制項提供的值(上面是從EventArgs去取的),而直接從資料來源本身去取,這裡就一定保證了資料的平衡性。我是這樣得到差值的(DataSet某Row):
decimal v = (decimal)pdRow["PayMoney", DataRowVersion.Proposed] - (decimal)pdRow["PayMoney", DataRowVersion.Current];
這裡就算控制項本身發生問題而導致資料顯示錯誤的話,但我們實際上的資料也是正確的(平衡)。只要在同步完畢之後,調用:
dataGridView.UpdateCurrentRow();
介面和資料來源保持一致了。上面可能是特例,但是原則我認為應該這樣做。希望對各位有啟發。~ ^^