­

Prism 源碼解讀5-數據綁定和命令

介紹

WPF本身就支援通知、綁定和命令,實現ViewModel和VIew之間的通訊,但相對來說功能比較少,Prism擴充了這些功能並提供更加強有力,簡潔的數據綁定和命令。

0 綁定通知

WPF的綁定通知需要實現INotifyPropertyChanged介面,也就是實現一個屬性改變事件,用來通知UI屬性改變了,讓UI更新。該事件需要一個事件參數new PropertyChangedEventArgs(propertyName)傳入屬性的名字,這樣的調用方式比較繁瑣。

Prism擴充了WPF的綁定通知。提供了BindableBase 實現了 INotifyPropertyChanged介面,並使用CallerMemberName獲取屬性名字。這樣就解決了屬性改變事件調用繁瑣的問題。同時在內部還是對相等值進行了過濾。

1585984101837

1585985493521

簡單愉快的調用吧

1585985633084

只需要使用SetProperty方法就可以自動更新UI了。

值得注意的是OnPropertyChanged還提供了對Expression的支援

1585986210800

也就是主動調用OnPropertyChanged(()=>this.PropertyName),也可以觸發UI響應。

1 命令

DelegateCommand

WPF命令和通知有點類似,命令需要實現ICommand介面,實現Execute方法,命令狀態CanExecute和命令狀態改變事件。並且WPF只實現了一個RoutedCommand。Prism提供了一個DelegateCommandBase命令基類實現ICommand,並擴充了子類DelegateCommand,大大簡化了命令調用方式

1585982600756

1585982617542

看到在基類中有_synchronizationContext執行緒同步上下文,用來保證命令執行的時候執行緒同步。

重點關注一下子類中的幾個方法

1585987365575

1585987399505

1585987411359

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

1585988063481

通過Expression,內部調用PropertyObserver.Observes()方法並將RaiseCanExecuteChaned方法傳入。

在PropertyObserver將Expression保存在一個鏈表,並每個節點都訂閱OnPropertyChanged事件。

1585988408971

CompositeCommand

Prism還提供了一個CompositeCommand命令

1585989655012

這個命令的功能跟其名字一樣,就是複合命令,命令集合。

  • 將DelegateCommand實例放到其中,每當調用CompositeCommand調用的時候會調用它保存的所有命令,
  • 命令集合中任何一個命令狀態改變,都會觸發CompositeCommand命令狀態的改變事件,導致CompositeCommand檢查集合中所有的命令狀態,首先會檢查IActiveAware,再檢查命令狀態,如果任何一個命令狀態是False,都會導致組合命令返回False

來看一下源碼

1585989673663

1585989692622

1585989705258

注意到,聚合命令也是通過執行緒上下文保持執行緒同步,同時看到有檢測IActiveAware介面,這個介面是什麼意思呢?其實就是查看該命令是否激活。這個介面有一個激活狀態屬性和一個激活狀態改變事件,

1585989967522

只要介面主動調用UpdateCommand.IsActive = true;命令就會被激活並觸發複合命令的激活狀態改變回調函數

1586001088755

1586001120188

在複合命令的ShouldExcute方法中檢查其激活狀態,命令集合中沒有激活命令,那麼複合命令的執行狀態也會改變。

命令執行和激活狀態都是差不多的介面,有狀態和狀態改變事件組成,感覺很多地方都有相似的模式,有點像訂閱模式,也有點像狀態機,包括一些Collection和Storage.

總結

主要講了下Prism提供的綁定通知和命令,學習到如何在WPF框架基礎上做一些封裝,如果可能甚至可以自己重新封裝一些功能更強大的命令來兼容Prism。