本文参考 Prism 官网示例
命令应用
Prism 提供了两种命令:DelegateCommand 和 CompositeCommand。
DelegateCommand
DelegateCommand 封装了两个委托:Execute 和 CanExecute,应用如下:
// view
<Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand"/>
// viewmodel
public 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,能够实现向前 / 向后导航。示例如下:
// GoForward
public 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;}
}
// GoBack
public 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>
// viewmodel
public 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();
}