天天看點

從PRISM開始學WPF(八)導航Navigation?

原文: 從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();