本文參考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();
}
轉載請注明出處,歡迎交流。