本文参考Prism官网示例
命令应用
Prism提供了两种命令:DelegateCommand和CompositeCommand。
DelegateCommand
DelegateCommand封装了两个委托:Execute和CanExecute,应用如下:
// view<Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand"/>// viewmodelpublic DelegateCommand ExecuteDelegateCommand { get; private set; }public MainWindowViewModel(){ ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);}private void Execute(){ UpdateText = $"Updated: {DateTime.Now}";}private bool CanExecute(){ return IsEnabled;}
CompositeCommand
CompositeCommand为复合命令,由多个子命令形成。当调用CompositeCommand时,将顺次调用每个子命令。默认状况下,当所有子命令CanExecute均返回true时才会执行CompositeCommand。应用办法如下:
// Project.Core中定义接口及实现public interface IApplicationCommands{ CompositeCommand SaveCommand { get; }}public class ApplicationCommands : IApplicationCommands{ private CompositeCommand _saveCommand = new CompositeCommand(); public CompositeCommand SaveCommand { get { return _saveCommand; } }}// App.xaml.cs中注册单例对象protected override void RegisterTypes(IContainerRegistry containerRegistry){ containerRegistry.RegisterSingleton< IApplicationCommands, ApplicationCommands>();}// viewmodel中增加子命令public TabViewModel(IApplicationCommands applicationCommands){ _applicationCommands = applicationCommands; UpdateCommand = new DelegateCommand(Update).ObservesCanExecute( () => CanUpdate); _applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);}// view中执行命令(需在对应的viewmodel的构造函数中传入IApplicationCommands实例)<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>
EventAggregator
EventAggregator是一种事件机制,解决了松耦合模块间的通信问题。应用办法如下:
// Project.core中申明事件类型public class MessageSentEvent : PubSubEvent<string>{}// viewmodel中公布事件IEventAggregator _ea;public MessageViewModel(IEventAggregator ea){ _ea = ea; // 公布事件的命令 SendMessageCommand = new DelegateCommand(SendMessage);}private void SendMessage(){ _ea.GetEvent<MessageSentEvent>().Publish(Message);}// viewmodel中订阅事件IEventAggregator _ea;public MessageListViewModel(IEventAggregator ea){ _ea = ea; _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived); // 如下形式能够过滤事件,可通过第二个参数指定解决线程 // _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));}private void MessageReceived(string message){ // hava a message}
RegionNavigation
区别于View Discovery和View Injection,RegionNavigation可通过region名称与要导航的视图名称实现更通用的视图导航性能,应用如下:
// 模块类中注册导航视图public void RegisterTypes(IContainerRegistry containerRegistry){ containerRegistry.RegisterForNavigation<ViewA>();}// xaml导航命令<Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" >Navigate to View A</Button>// viewmodel实现导航public DelegateCommand<string> NavigateCommand { get; private set; }public MainWindowViewModel(IRegionManager regionManager){ _regionManager = regionManager; NavigateCommand = new DelegateCommand<string>(Navigate);}private void Navigate(string navigatePath){ if (navigatePath != null) _regionManager.RequestNavigate("ContentRegion", navigatePath, NavigationCompleted);}// 可指定导航实现回调private void NavigationCompleted(NavigationResult result){ // ...}
INavigationAware接口
INavigationAware接口蕴含三个办法:OnNavigatedFrom、OnNavigatedTo、IsNavigationTarge。当ViewAViewModel及ViewBViewModel均实现了INavigationAware接口,ViewA导航到ViewB时,先调用ViewA的OnNavigatedFrom办法,而后调用ViewB的IsNavigationTarge,当其返回true时,调用OnNavigatedTo办法,若IsNavigationTarge返回false,创立新ViewB。示例如下:
public class ViewAViewModel : BindableBase, INavigationAware{ public void OnNavigatedTo(NavigationContext navigationContext) { // ... } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { // ... }}
IConfirmNavigationRequest接口
IConfirmNavigationRequest接口继承了INavigationAware接口,并增加了ConfirmNavigationRequest办法。若ViewAViewModel实现了IConfirmNavigationRequest接口,当ViewA导航到ViewB时,先调用ConfirmNavigationRequest办法,若continuationCallback()参数为true,将继续执行导航,执行OnNavigatedFrom办法;若continuationCallback()参数为false,进行导航。示例如下:
public class ViewAViewModel : BindableBase, IConfirmNavigationRequest{ public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) { bool result = true; if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No) result = false; continuationCallback(result); } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { } public void OnNavigatedTo(NavigationContext navigationContext) { }}
IRegionMemberLifetime接口
IRegionMemberLifetime接口只蕴含一个KeepAlive只读属性。其默认值为true,若其为false,则当该region导航到其它视图时,实现了该接口的以后视图将从IRegion.Views汇合中移除并回收。若为true,即便导航到其它视图,该视图仍然存在于IRegion.Views汇合。示例如下:
public class ViewAViewModel : BindableBase, IRegionMemberLifetime{ public bool KeepAlive { get { return false; } }}
参数传递
可应用NavigationParameters实现导航时的参数传递,应用办法如下:
// 导航命令private void PersonSelected(Person person){ var parameters = new NavigationParameters(); parameters.Add("person", person); if (person != null) _regionManager.RequestNavigate("PersonDetailsRegion", "PersonDetail", parameters);}// 参数解决public void OnNavigatedTo(NavigationContext navigationContext){ var person = navigationContext.Parameters["person"] as Person; // ...}public bool IsNavigationTarget(NavigationContext navigationContext){ var person = navigationContext.Parameters["person"] as Person; // ...}
Navigation Journal
Navigation Journal能够记录导航的过程,其通过IRegionNavigationJournal接口实现。通过Navigation Journal,能够实现向前/向后导航。示例如下:
// GoForwardpublic class PersonListViewModel : BindableBase, INavigationAware{ IRegionNavigationJournal _journal; public DelegateCommand GoForwardCommand { get; set; } public PersonListViewModel(IRegionManager regionManager) { ... GoForwardCommand = new DelegateCommand(GoForward, CanGoForward); } // IRegionNavigationJournal.GoBack到行至此 public void OnNavigatedTo(NavigationContext navigationContext) { _journal = navigationContext.NavigationService.Journal; GoForwardCommand.RaiseCanExecuteChanged(); } private void GoForward() { _journal.GoForward(); } private bool CanGoForward() { return _journal != null && _journal.CanGoForward; }}// GoBackpublic class PersonDetailViewModel : BindableBase, INavigationAware{ IRegionNavigationJournal _journal; public DelegateCommand GoBackCommand { get; set; } public PersonDetailViewModel() { GoBackCommand = new DelegateCommand(GoBack); } public void OnNavigatedTo(NavigationContext navigationContext) { _journal = navigationContext.NavigationService.Journal; } private void GoBack() { _journal.GoBack(); }}
InvokeCommandAction
Prism提供了InvokeCommandAction以使ViewModel解决View的事件,示例如下:
// view xaml<ListBox ItemsSource="{Binding Items}" SelectionMode="Single"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <prism:InvokeCommandAction Command="{Binding SelectedCommand}" TriggerParameterPath="AddedItems" /> </i:EventTrigger> </i:Interaction.Triggers></ListBox>// viewmodelpublic DelegateCommand<object[]> SelectedCommand { get; private set; }public MainWindowViewModel(){ ... SelectedCommand = new DelegateCommand<object[]>(OnItemSelected);}private void OnItemSelected(object[] selectedItems){ if (selectedItems != null && selectedItems.Count() > 0) SelectedItemText = selectedItems.FirstOrDefault().ToString();}