原文: 從PRISM開始學WPF(八)導航Navigation?
0x6Navigation
Basic Navigation
Prism中的Navigation提供了一種類似導航的功能,他可以根據使用者的輸入,來重新整理UI。
先看一個最簡單的例子,通過按鈕來導航到一個視圖,在這裡,視圖被注冊為Navication。
public void Initialize()
{
_container.RegisterTypeForNavigation<ViewA>();
_container.RegisterTypeForNavigation<ViewB>();
}
Shell 視圖中設定兩個Button并且綁定下面這個帶參數的指令:
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);
}
<DockPanel LastChildFill="True">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5" >
<Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" Margin="5">Navigate to View A</Button>
<Button Command="{Binding NavigateCommand}" CommandParameter="ViewB" Margin="5">Navigate to View B</Button>
</StackPanel>
<ContentControl prism:RegionManager.RegionName="ContentRegion" Margin="5" />
</DockPanel>
RegionManager通過RequestNavigate方法來擷取已經注冊的Navigation并且綁定到Region上去。
當需要根據調用結果來處理一些事情,可以使用下面這個方法:
void RequestNavigate(string regionName, string source, Action<NavigationResult> navigationCallback);
當然,上面這個方法是在Shell中調用的,但,有些時候,我們需要View或者ViewModel也參與到Navigation中來,比如當你Request一個Navigation的時候,希望navigation本身顯示一些資訊,為此 Prism為我們提供了一個INavigationAware 接口。
//
// Summary:
// Provides a way for objects involved in navigation to be notified of navigation
// activities.
public interface INavigationAware
{
//
// Summary:
// Called to determine if this instance can handle the navigation request.
//
// Parameters:
// navigationContext:
// The navigation context.
//
// Returns:
// true if this instance accepts the navigation request; otherwise, false.
bool IsNavigationTarget(NavigationContext navigationContext);
//
// Summary:
// Called when the implementer is being navigated away from.
//
// Parameters:
// navigationContext:
// The navigation context.
void OnNavigatedFrom(NavigationContext navigationContext);
//
// Summary:
// Called when the implementer has been navigated to.
//
// Parameters:
// navigationContext:
// The navigation context.
void OnNavigatedTo(NavigationContext navigationContext);
}
如果想要Navigation的目标也參與到Navigation的過程當中,隻需要讓你的viewmodel實作這個接口,然後在這些方法裡編寫你的代碼就可以了。
IsNavigationTarget方法設定了是否被允許設定為導航的目标,當他的傳回值為Fasle的時候,将不會被“導航”到它。
在 19-NavigationParticipation
的例子中,Region的目标是:
<TabControl prism:RegionManager.RegionName="ContentRegion" Margin="5" />
TabControl在設定為Region的時候,加載View時會自動建立Page來存放View,如果“導航”到同一個View他會在Page中找到他,并且顯示出來。但如果IsNavigationTarget傳回False的話,就不會顯示之前的Page而是建立了一個新的Page來加載View。
PassingParameters帶參數的導航
使用Navigation的時候,将資料源帶到新的NavigationTarget中去,然後Target應用這些資料。這将使用到navigation的NavigationContext參數:
private void PersonSelected(Person person)
{
var parameters = new NavigationParameters();
parameters.Add("person", person);
if (person != null)
_regionManager.RequestNavigate("PersonDetailsRegion", "PersonDetail", parameters);
}
在Target的OnNavigatedTo方法中使用:
public void OnNavigatedTo(NavigationContext navigationContext)
{
var person = navigationContext.Parameters["person"] as Person;
if (person != null)
SelectedPerson = person;
}
當導航變更的時候你需要一些提示框,需要實作IConfirmNavigationRequest
他有一個ConfirmNavigationRequest方法來進行一些判斷。
在上面的例子中,我們在view之間跳轉的時候,viewA 和viewB是被緩存的,但是有時候,我們跳轉到B的時候想要銷毀A,怎麼來做呢?
在View或ViewModel上實作IRegionMemberLifetime接口,并将KeepAlive屬性的值設定為false。
journal
journal 實作一種類似浏覽器前進後退按鈕一樣的效果,當一個region 有多個view的時候,他會自動記錄view的加載順序,然後在view之間來回切換。
Prism中是通過IRegionNavigationJournal來實作的,在視圖加載時,講道理,可以無限級前進和後退的,我自己在官方的例子上加了一個視圖也完美運作。
public void OnNavigatedTo(NavigationContext navigationContext)
{
_journal = navigationContext.NavigationService.Journal;
}
然後使用 :
_journal.GoBack();
或者
_journal.GoForward();