Prism 原始碼解讀5-資料繫結和命令
阿新 • • 發佈:2020-04-04
## 介紹
WPF本身就支援通知、繫結和命令,實現ViewModel和VIew之間的通訊,但相對來說功能比較少,Prism擴充了這些功能並提供更加強有力,簡潔的資料繫結和命令。
## 0 繫結通知
WPF的繫結通知需要實現INotifyPropertyChanged介面,也就是實現一個屬性改變事件,用來通知UI屬性改變了,讓UI更新。該事件需要一個事件引數new PropertyChangedEventArgs(propertyName)傳入屬性的名字,這樣的呼叫方式比較繁瑣。
Prism擴充了WPF的繫結通知。提供了BindableBase 實現了 INotifyPropertyChanged介面,並使用CallerMemberName獲取屬性名字。這樣就解決了屬性改變事件呼叫繁瑣的問題。同時在內部還是對相等值進行了過濾。
![1585984101837](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708843-1702991048.png)
![1585985493521](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708877-1354432512.png)
簡單愉快的呼叫吧
![1585985633084](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708878-1901199377.png)
只需要使用SetProperty方法就可以自動更新UI了。
值得注意的是OnPropertyChanged還提供了對Expression的支援
![1585986210800](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708877-568046699.png)
也就是主動呼叫OnPropertyChanged(()=>this.PropertyName),也可以觸發UI響應。
## 1 命令
### DelegateCommand
WPF命令和通知有點類似,命令需要實現ICommand介面,實現Execute方法,命令狀態CanExecute和命令狀態改變事件。並且WPF只實現了一個RoutedCommand。Prism提供了一個DelegateCommandBase命令基類實現ICommand,並擴充了子類DelegateCommand,大大簡化了命令呼叫方式
![1585982600756](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708879-1353104735.png)
![1585982617542](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708877-954606042.png)
看到在基類中有_synchronizationContext執行緒同步上下文,用來保證命令執行的時候執行緒同步。
重點關注一下子類中的幾個方法
![1585987365575](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708878-1142200719.png)
![1585987399505](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708877-459954683.png)
![1585987411359](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708878-2100159727.png)
1.ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
- 這個命令宣告方式,如果命令狀態發生變化的時候需要主動呼叫RaiseCanExecuteChanged方法來觸發命令狀態改變事件。
2.DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled);
- 可以看到這種宣告方式,提供了一個ObservesProperty方法,不需要顯示呼叫命令狀態改變事件。
3.DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled);
- 這種宣告方法提供ObservesCanExecute方法,直接觀測命令狀態改變事件和屬性。
4.ExecuteGenericDelegateCommand = new DelegateCommand(ExecuteGeneric).ObservesCanExecute(() => IsEnabled);
- 這是一個使用泛型帶引數的宣告方式,
看一下內部怎麼實現這種簡單而強大的功能
![1585988022789](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708878-184586764.png)
![1585988063481](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708878-2099308553.png)
通過Expression,內部呼叫PropertyObserver.Observes()方法並將RaiseCanExecuteChaned方法傳入。
在PropertyObserver將Expression儲存在一個連結串列,並每個節點都訂閱OnPropertyChanged事件。
![1585988408971](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708844-977515147.png)
### CompositeCommand
Prism還提供了一個CompositeCommand命令
![1585989655012](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708879-975859313.png)
這個命令的功能跟其名字一樣,就是複合命令,命令集合。
- 將DelegateCommand例項放到其中,每當呼叫CompositeCommand呼叫的時候會呼叫它儲存的所有命令,
- 命令集合中任何一個命令狀態改變,都會觸發CompositeCommand命令狀態的改變事件,導致CompositeCommand檢查集合中所有的命令狀態,首先會檢查IActiveAware,再檢查命令狀態,如果任何一個命令狀態是False,都會導致組合命令返回False
來看一下原始碼
![1585989673663](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708879-1481801842.png)
![1585989692622](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708880-760043693.png)
![1585989705258](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708914-1826322243.png)
注意到,聚合命令也是通過執行緒上下文保持執行緒同步,同時看到有檢測IActiveAware介面,這個介面是什麼意思呢?其實就是檢視該命令是否啟用。這個介面有一個啟用狀態屬性和一個啟用狀態改變事件,
![1585989967522](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708915-1986517383.png)
只要介面主動呼叫UpdateCommand.IsActive = true;命令就會被啟用並觸發複合命令的啟用狀態改變回調函式
![1586001088755](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708915-1762675636.png)
![1586001120188](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200404201708915-1670037345.png)
在複合命令的ShouldExcute方法中檢查其啟用狀態,命令集合中沒有啟用命令,那麼複合命令的執行狀態也會改變。
命令執行和啟用狀態都是差不多的介面,有狀態和狀態改變事件組成,感覺很多地方都有相似的模式,有點像訂閱模式,也有點像狀態機,包括一些Collection和Storage.
## 總結
主要講了下Prism提供的繫結通知和命令,學習到如何在WPF框架基礎上做一些封裝,如果可能甚至可以自己重新封裝一些功能更強大的命令來相容