MVVM框架從WPF移植到UWP遇到的問題和解決方法

durow發表於2015-10-15

MVVM框架從WPF移植到UWP遇到的問題和解決方法

0x00 起因

這幾天開始學習UWP了,之前有WPF經驗,所以總體感覺還可以,看了一些基礎概念和主題,寫了幾個測試程式,突然想起來了前一段時間在WPF下寫的簡易的MVVM框架(MVVM模式和在WPF中的實現),都是.NET平臺的,移到通用類庫裡只要複製貼上就可以了吧。抱著這個心態試了下,結果程式碼一片紅,折騰了一下午總算搞得差不多了,第二天寫了個測試試了下感覺基本問題應該是解決了。現在總結一下自己踩到的坑。

0x01 命令繫結

之前在WPF中實現ICommand介面時,將檢查Command是否可以執行的_canExecute新增到CommandManager的RequerySuggested事件中(詳細見MVVM模式解析和在WPF中的實現(三)命令繫結),這樣在出現可能會影響命令執行狀態的事件時,CommandManager會觸發事件對命令的可執行狀態進行檢查,並將檢查方法的返回值賦給命令繫結控制元件的IsEnable屬性上。這樣我們只要指定檢查命令執行狀態的方法即可,系統會自動檢查。不過在UWP中這個CommandManager沒有了,因此將無法再執行自動的命令可執行狀態的檢查。剛開始遇到這個問題時,按下Ctrl+.的組合鍵提示我引用WPF中的dll可以解決問題,按照提示操作了之後紅色下劃線果然沒了,可是編譯時提示我有衝突還是什麼,後來去網上查如何解決這個衝突,自然沒搞定。不過找到了MVVMLight的作者寫的一篇文章http://blog.galasoft.ch/posts/2015/01/re-enabling-the-commandmanager-feature-with-relaycommand-in-mvvm-light-v5/,看來CommandManager是真沒了。

為什麼要在UWP中移除CommandManager呢,我也沒找到答案,個人猜測應該是這個操作浪費了太多的資源吧,特別在手機終端資源(包括電量)是很有限的。這個事件在MSDN中的描述意思也很模糊

也就是說CommandManager認為某個行為會影響到命令執行狀態就會觸發事件執行檢查。我在WPF中一直使用這個功能從未遇到過問題,由此可見能觸發這個檢查的事件或其它狀態改變還是很多的,也就是說對命令執行狀態的檢查是很頻繁的,而且當觸發檢查時會對所有註冊了狀態檢查的命令檢查一遍。可能檢查100次才會有一次狀態改變,也可能程式執行整個過程中狀態檢查結果都沒有變化,所以這個冗餘操作太多了。

那麼在UWP中我們應該怎麼檢查命令的執行狀態呢,剛開始我打算自己寫個事件,繫結命令時把檢查執行狀態的方法訂閱那個事件,然後設定個Timer來定時觸發事件檢查執行狀態,這絕對是個餿主意,馬上就否決了。後來考慮在ViewModel中的屬性發生改變時進行檢查,也是很多冗餘操作,而且這種檢查也很不完善。後來想想算了,乾脆手動檢查吧,這樣檢查的針對性強。具體做法就是在命令的型別中新增觸發檢查的方法RaiseCanExecuteChanged()方法。

 

0x02 事件繫結到命令

其實這個問題非常好解決的,結果我卻踩到坑裡一個多小時才爬出來。先說下事件繫結,再說下坑的事情。之前在WPF中將事件繫結到命令靠的是Interactivity.dll,在UWP中換了另外兩個dll:Microsoft.Xaml.Interactivity.dll和Microsoft.Xaml.Interactions.dll,過方法類似。我的VS採用的是預設安裝,這兩個dll在C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1\ExtensionSDKs\BehaviorsXamlSDKManaged\12.0\References\CommonConfiguration\Neutral這個位置。新增這兩個dll的引用後就可以在XAML中實現事件繫結到命令了。下圖程式碼繫結了主頁面的PointerMoved事件至ViewModel中的CmdMouseMove命令。

 

特別值得一提的是之前在WPF中為了在事件繫結到命令後能夠把時間的EventArgs傳給命令,我們自己寫了一個MyEventCommand類(MVVM設計模式和WPF中的實現(四)事件繫結),在UWP中就不需要了,InvokeCommandAction在不繫結CommandParameter的情況下預設就傳遞EventArgs引數,但當繫結了CommandParameter後傳給Command的則為CommandParameter繫結的物件而不是事件的EventArgs引數。

這個應該是很簡單的,結果我在測試的時候在類庫的專案中引用了那兩個dll,沒有在測試專案中引入,所以在測試專案MainPage的XAML中進行引用名稱空間時總是提示我不存在。記得以前剛換Windows8.1的時候遇到過類似問題,原因是系統會把來自網路的dll加鎖,只要手動解鎖就可以用了,翻了下之前那篇文章,也沒在win10中看到有dll加鎖啊。又開始懷疑dll版本不對,搜了好半天,最後發現是測試專案中沒有引入那兩個dll,反倒類庫中沒有必要引入。

0x03 其他一些問題

由於剛開始學習UWP開發,缺乏相關經驗,因此在WPF中的View和ViewModel的通訊和依賴注入不知道是不是適合於UWP,所以只是暫時把功能移過去,有待後面邊學習邊測試邊修改。好吧,其實後面學習過程中寫測試程式的話應該也不會用MVVM的。

另外移植過程中還發現從Type建立例項的方法變了,以前是這麼寫的:

type.Assembly.CreateInstance(type.FullName);

在UWP中需要這麼寫:

type.GetConstructor(Type.EmptyTypes).Invoke(parameters);

還有Dispatcher變成了CoreDispatcher等其他一些問題都與MVVM無關了,而且處理起來也都很容易,就不再討論了。

0x04 示例

之前WPF版的MVVM框架還沒來得及寫示例,UWP版的反倒寫了。示例很簡單,介面如下圖所示:

 

說明一下:

1.上邊的TextBox顯示的是當前滑鼠相對於窗體的位置,隨著滑鼠移動顯示數值會變化,方法是繫結了MainPage的PointerMoved事件,這說明了命令繫結執行正常,事件繫結命令並傳遞事件的引數也執行正常。

2.滑鼠位置資訊正確顯示說明ViewModel中屬性的資料繫結正常。

3.下面ListView資料正確顯示說明繫結ViewModel中的集合屬性正常。

4.按下Add會插入一條資料,按下Delete會刪除選中資料,按下Clear會清空列表,說明命令繫結正常。

5.當無選中項時Delete按鈕禁用,說明命令執行狀態檢查正常。

0x05 相關下載

https://github.com/durow/AyxMVVM

 


更多內容歡迎訪問我的部落格:http://www.durow.vip

相關文章