C# WPF MVVM 實戰 – 2.2


上一篇,開始了采購訂單的開發,談完 Combo Box 怎樣綁定到 ViewModel 的集合,還把選定項的其他信息一並顯示在 View 的另一個控件(TextBlock)。這次繼續談表頭的部分,和介紹明細行的綁定。

由於單純把單一個普通控件綁到 ViewModel 屬性比較簡單,我只介紹一個,其他的請自行看代碼。

VIEWMODELS

就拿單據號來看看。它在 View 上是一個 TextBox,在 Model 內是 string,沒有比這更簡單的了。以下是 View 的 XAML:

image

然后是 ViewModel 的相關代碼:

image

代碼是接着上一篇來寫下去的。上次的部分我收了起來,需要的請看上一篇

這里實在沒有什么好說的,唯一的是,我在 get 和 set 都直接讀取或寫入業務類實例的屬性內,這免去了一層映射。不喜歡把 Model 類直接暴露到 View 的,不喜歡我這方式的,就只能在 ViewModel 多保存一個private/internal string,在保存或更新時候你自己映射到 Model 實例。絕大多數情況中,我認為沒有這必要這樣分隔。

然后,我直接談談明細行了。它有好幾個有趣的地方。

image

首先是添加、刪除行按鈕。其實很多第三方控件,都已經有這些功能,而且實現得比我這樣寫好很多,比如,右擊帶出菜單來刪行,最后一行有個添加行按鈕等等。要我自己弄到那樣要花點功夫,而且跑題了。就先這樣吧。

說 WPF 一切都綁定。是的,連命令也可以綁定。看看這兩個按鈕的 XAML:

image

如果你過往用 Win Form,現在用 WPF 而且正在學習 MVVM,最好是把 WinForm 的一切忘掉。Button 的命令不是雙擊設計界面生成句柄來做的,是上面這做法。Command 綁定,要求是綁到實現了 ICommand 接口的實例,在我第一篇已經提到過 RelayCommand,你可以用它,或者你喜歡的用別的也行,比如 DelegateCommand。

按照上面 XAML 的寫法,意思是 DataContext,即 ViewModel 內,有兩個 public 屬性 (AddRowCommand / DeleteRowCommand),它們都是實現了 ICommand 接口的。那么,看看 ViewModel 代碼,先看看 AddRowCommand,用來添加新明細行的:

image

有人不喜歡我這種寫法,他們喜歡在 ViewModel 的構造函數,初始化時候,把 addRowCommand 通通創建實例先,get 內直接返回 addRowCommand。我沒覺得有什么明顯分別,你喜歡。

由於上一篇的代碼內,已經寫了,PoDetails 是 ObserverableCollection<T>,所以當你用代碼添加行時候,視圖會收到通知,就會更新顯示。單純用 List 之類來做 PoDetails 集合,或者其他沒有實現 INotifyCollectionChanged 的集合,是做不到這效果的。

第一篇也已經提到,RelayCommand 的設計,當構造函數是一個參數時候,CanExecute 永遠返回 True,這命令是永遠都能執行,Button 永遠都是 enable 的。要 disable 的時候,做法可以看看我 ViewModel 的另一個 ICommand 屬性,DeleteRowCommand:

image

當我沒有點擊任何行,沒有選任何行,我希望“刪除行”按鈕被禁用,disable,灰色。要做到這效果,我需要知道用戶有沒有選擇了 GridView 內的行。所以我加了一個屬性來記錄當前選定的行,是哪個,它的類型,當然是行記錄業務對象 PurchaseOrderDetail:

image

 

只要把 GridView 的選中行,綁到 CurrentRow,然后讓deleteRowCommand 內 CanExecute 委托(構造函數第二個參數)來檢查 CurrentRow 是否為空 null,就能做到了。GridView 的選中行,綁到 CurrentRow 的 XAML 代碼如下:

image

另外有了 CurrentRow,刪除行時候視圖觸發命令時候,也不需要參數,不用告訴 ViewModel 當前行是哪個,因為當前行就是 CurrentRow。要刪除它,就像 ViewModel 的 DeleteRow() 第 130 行代碼那樣,直接 remove() 它即可。

由於 CurrentRow 為 null 時候(用戶沒有選任何行的時候),deleteRowCommand 的 CanExecute 會返回 False,這命令是無法執行的,界面按鈕是 disable 狀態,所以在 DeleteRow 連檢查 CurrentRow 是否為空等的代碼也可以省掉了。代碼能運行到 DeleteRow() 時候,CurrentRow 必定有值,remove 代碼不會拋異常。

說了半天,給大家看看效果圖:

沒有任何行的時候

image

添加了行,但 GridView 沒有焦點,沒選行的時候

image

添加了行,選中了的時候

image

刪除了行,沒有再次選中行的時候

 

 

 

 

image

 

ViewModel 代碼的文本,我下一次才貼出來,那樣比較完整。

接下去,下一次,會講物料號的綁定。它的特別之處,在於物料號是選項,選項列表來自系統的 Inventory 集合,這集合,是所有明細行共用的,不是一行一個新集合。MVVM 模式下,怎樣能做到?下回介紹

我在這群里,歡迎加入交流:
開發板玩家群 578649319開發板玩家群 578649319
硬件創客 (10105555)硬件創客 (10105555)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM