背景:
在模塊的UI中包含 TreeView 控件,在該樹形控件的每一節點前面定義了一個復選框,如圖
需求:
在兩個不同的應用程序中使用該控件,而它在不同應用程序中的外觀則並不一致,按照本例,即一個顯示復選框,一個不顯示。
問題:
解決該問題的一個難處在於,Prism框架本身的設計原則——此 View 會被添加到主程序的 Shell 的 Region 中,所以在主程序中不能直接來控制該 View 的屬性及其邏輯。
思路:
利用 EventAggregator 使得主程序與模塊間進行通信,從而間接地達到我們的目的。
實現:
首先,在模塊的 View 所對應的 ViewModel 中添加一個屬性 ShowCheckbox,如下:
public bool ShowCheckbox { get { return this.showCheckBox; } set { this.SetProperty(ref this.showCheckBox, value); } }
其中的 SetProperty 方法是在 BindableBase 類(由 Prism.MVVM 庫提供)的方法,其介紹可點擊這里,這樣寫的好處:1. 省去自己再實現 INotifyPropertyChanged 接口;2. 避免可能在類似 RaisePropertyChanged("XXX") 語句中寫錯屬性的名字。只要當我們的 ViewModel 類繼承了 BindableBase 類,就可以這樣來定義那些值被更改后需要通知UI的屬性。
並在 View 中為其添加綁定,如下 CheckBox 的 Visibility 屬性的綁定:
<UserControl.Resources> <HierarchicalDataTemplate x:Key="HierarchicalView" ItemsSource="{Binding SubCategories}"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch"> <CheckBox IsChecked="{Binding IsChecked}" Margin="6,6,5,0" Visibility="{Binding ShowCheckbox,ElementName=treeViewControl,Converter={StaticResource BoolToVisibilityConverter}}" /> <TextBlock Text="{Binding Name}" FontSize="20" /> <StackPanel.ToolTip> <TextBlock VerticalAlignment="Center" Text="{Binding Name}" TextWrapping="Wrap" MaxWidth="200" /> </StackPanel.ToolTip> </StackPanel> </HierarchicalDataTemplate> </UserControl.Resources>
然后,我們需要在底層庫 Infrastructure 中定義一個事件,主程序與模塊就是通過該事件來進行通信,以達到修改模塊中 UI 的值,代碼如下:
public class ControlVisibleEvent : PubSubEvent<bool> { }
接下來,就是對該事件進行訂閱與發布,自然地,我們在模塊中來訂閱上述事件,代碼如下:
this.EventAggregator.GetEvent<DemoBase.ControlVisibleEvent>().Subscribe((value) => { this.ShowCheckbox = value; });
在訂閱事件時,我們獲取值並把獲取到的值傳給 ViewModel 的 ShowCheckbox 屬性,再通過WPF的通知機制以達到UI的變化。
在主程序中,我們發布該事件,發布時,需要考慮的問題是在何時發布,這里我們選擇在加載模塊完成的事件中進行發布,代碼如下(注意其中的高亮代碼):
public MainWindow(IEventAggregator eventAggregator, IModuleManager moduleManager) { InitializeComponent(); this.EventAggregator = eventAggregator; this.ModuleManager.LoadModuleCompleted += ModuleManager_LoadModuleCompleted; } void ModuleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e) { this.EventAggregator.GetEvent<DemoBase.ControlVisibleEvent>().Publish(false); }
這時,在不同的應用程序中,只要修改在發布事件時的值,即可達到模塊中UI的改變。
備注:
實現此需求的不止上述方法,此外,利用 Region 對象的 RegionContext 屬性也是一種不錯的辦法,后續可以再進行研究。