Wpf Prism 導航(參數傳遞,路由守衛,路由記錄)

十年河東,十年河西,莫欺少年窮

學無止境,精益求精

1、新建項目wpfApp5,添加Nuget引用,並初始化App.xaml 及 cs 類

 app.xaml 如下:

<Prism:PrismApplication x:Class="WpfApp5.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp5"
             xmlns:Prism="http://prismlibrary.com/"  
                        >
    <Application.Resources>
         
    </Application.Resources>
</Prism:PrismApplication>
View Code

cs 類如下:

using DryIoc;
using Prism.DryIoc; 
using Prism.Ioc;
using Prism.Modularity;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using WpfApp5.UserControls;
using WpfApp5.UserControls.Models;
using WpfApp5.Views;

namespace WpfApp5
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            //設置啓動窗體爲MainView
            return Container.Resolve<MainView>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<viewA, viewAModel>();////如果不聲明名字爲viewA , 默認和類名一致
            containerRegistry.RegisterForNavigation<viewB, viewBModel>("viewB");////如果不聲明名字爲viewB , 默認和類名一致
            containerRegistry.RegisterForNavigation<viewC, viewCModel>();////如果不聲明名字爲viewC , 默認和類名一致
        }
    }
}
View Code

說明:

xaml 中引入 Prism

             xmlns:Prism="http://prismlibrary.com/"  

更改標籤爲:

<Prism:PrismApplication> 。。。。。。 </Prism:PrismApplication>

設置啓動窗體爲 MainView,這裏需要說明的是:窗體必須放在Views文件夾下而且必須以View結尾,ViewModel必須放在ViewModels文件夾下面,文件必須以ViewModel結尾。

App.xaml.cs 中註冊了三個導航窗體(用戶控件),分別爲:viewA、viewB、viewC,及啓動窗體MainView

2、聲明 MainView 

新建文件夾 Views 和 數據上下文文件夾 ViewModels,在Views文件夾中新建 MainView窗體(必須以View結尾),在ViewModels文件夾中新建 MainViewModel 上下文類(必須以Model結尾)

MainView.xaml 如下

<Window x:Class="WpfApp5.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5.Views" 
        xmlns:Prism="http://prismlibrary.com/"  
        Prism:ViewModelLocator.AutoWireViewModel="True"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <Button Content="viewA" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewA"></Button>
            <Button Content="viewB" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewB"></Button>
            <Button Content="viewC" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewC"></Button>
            <Button Content="返回上一頁" Margin="5" Height="35" Width="100" Command="{Binding BtnBack}"></Button>
            <Button Content="返回下一頁" Margin="5" Height="35" Width="100" Command="{Binding BtnForward}"></Button>
        </StackPanel>

        <ContentControl Grid.Row="1" Prism:RegionManager.RegionName="ContentRegion"/>
    </Grid>
</Window>
View Code

 viewModel 類如下

    public class MainViewModel : BindableBase
    {
        public DelegateCommand<string> BtnCommand { get; private set; }
        public DelegateCommand BtnBack { get; private set; }
        public DelegateCommand BtnForward { get; private set; }
        /// <summary>
        /// 區域管理器-跳轉相關
        /// </summary>
        private readonly IRegionManager regionManager;
        /// <summary>
        /// 用於保存路由跳轉記錄
        /// </summary>
        private  IRegionNavigationJournal journal;

        public MainViewModel(IRegionManager regionManager)
        {
            BtnCommand = new DelegateCommand<string>(BtnRedirect);
            BtnBack = new DelegateCommand(Back);
            BtnForward = new DelegateCommand(Forward);
            this.regionManager = regionManager;
        }

        /// <summary>
        /// 頁面跳轉
        /// </summary>
        /// <param name="parma"></param>
        private void BtnRedirect(string parma)
        {
            NavigationParameters keys = new NavigationParameters();
            keys.Add("name", "河南大學");
            keys.Add("id", "58");
            regionManager.Regions["ContentRegion"].RequestNavigate(parma,navigationCallback, keys);
        }

        private void navigationCallback(NavigationResult  navigation)
        {
            if (navigation.Result.Value)
            {
                //如果跳轉成功,則存儲跳轉記錄
                journal = navigation.Context.NavigationService.Journal;
            }
        }

        /// <summary>
        /// 返回上一頁
        /// </summary>
        private void Back()
        {
            if (journal.CanGoBack)
            {
                journal.GoBack();
            }
        }

        /// <summary>
        /// 返回下一頁
        /// </summary>
        private void Forward()
        {
            if (journal.CanGoForward)
            {
                journal.GoForward();
            }
        }
    }
View Code

說明如下:

必須繼承自 BindableBase

public class MainViewModel : BindableBase

聲明按鈕命令事件、區域管理、路由

        public DelegateCommand<string> BtnCommand { get; private set; }
        public DelegateCommand BtnBack { get; private set; }
        public DelegateCommand BtnForward { get; private set; }
        /// <summary>
        /// 區域管理器-跳轉相關
        /// </summary>
        private readonly IRegionManager regionManager;
        /// <summary>
        /// 用於保存路由跳轉記錄
        /// </summary>
        private  IRegionNavigationJournal journal;

        public MainViewModel(IRegionManager regionManager)
        {
            BtnCommand = new DelegateCommand<string>(BtnRedirect);
            BtnBack = new DelegateCommand(Back);
            BtnForward = new DelegateCommand(Forward);
            this.regionManager = regionManager;
        }

帶有參數的頁面跳轉如下:

        /// <summary>
        /// 頁面跳轉-帶有參數
        /// </summary>
        /// <param name="parma"></param>
        private void BtnRedirect(string parma)
        {
            NavigationParameters keys = new NavigationParameters();
            keys.Add("name", "河南大學");
            keys.Add("id", "58");
            regionManager.Regions["ContentRegion"].RequestNavigate(parma,navigationCallback, keys);
        }

        private void navigationCallback(NavigationResult  navigation)
        {
            if (navigation.Result.Value)
            {
                //如果跳轉成功,則存儲跳轉記錄
                journal = navigation.Context.NavigationService.Journal;
            }
        }

navigationCallback 爲回調事件,用於記錄導航

返回上一頁、下一頁代碼如下:

        /// <summary>
        /// 返回上一頁
        /// </summary>
        private void Back()
        {
            if (journal.CanGoBack)
            {
                journal.GoBack();
            }
        }

        /// <summary>
        /// 返回下一頁
        /// </summary>
        private void Forward()
        {
            if (journal.CanGoForward)
            {
                journal.GoForward();
            }
        }

3、用戶控件 viewA  (無需遵守Prism的規則)

xaml 如下:

<UserControl x:Class="WpfApp5.UserControls.viewA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp5.UserControls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="I am viewA" FontSize="24"/>
            <TextBlock Text="{Binding Name}" FontSize="24"/>
            <TextBlock Text="{Binding Id}" FontSize="24"/>
        </StackPanel>
    </Grid>
</UserControl>

綁定的Name 和 Id 爲參數傳遞的值

viewModel類如下:

    public class viewAModel : BindableBase, INavigationAware, IConfirmNavigationRequest
    { 
        public viewAModel()
        {

        }

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                name = value;
                RaisePropertyChanged();
            }
        }
        private string id;
        public string Id
        {
            get { return this.id; }
            set
            {
                id = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        /// 路由保衛--可以在此方法中判斷是否允許跳轉--continuationCallback 會通知 OnNavigatedFrom 方法是否跳轉
        /// </summary>
        /// <param name="navigationContext"></param>
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            var isok = false;
            if (MessageBox.Show("確定跳轉嗎", "溫馨提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                isok = true;
            }
            continuationCallback(isok);
        }

       

        /// <summary>
        /// 進入該viewModel時,是否創建新的viewModel對象
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        /// <summary>
        /// 離開該viewModel執行 和 路由保衛配合使用
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
             //離開時 可能會涉及到一些數據處理,在此不做演示
        }

        /// <summary>
        /// 進入該viewModel時執行
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            if (navigationContext.Parameters.ContainsKey("name"))
            {
                this.Name = navigationContext.Parameters.GetValue<string>("name");
            }
            if (navigationContext.Parameters.ContainsKey("id"))
            {
                this.Id = navigationContext.Parameters.GetValue<string>("id");
            }
        }
    }
View Code

說明如下:

繼承自 BindableBase,INavigationAware, IConfirmNavigationRequest

    public class viewAModel : BindableBase, INavigationAware, IConfirmNavigationRequest

BindableBase(用於雙向綁定),INavigationAware(用於導航跳轉), IConfirmNavigationRequest(用於導航跳轉前,確認是否跳轉,即路由保衛)

1、進入用戶控件viewModel時執行

        /// <summary>
        /// 進入該viewModel時執行
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            if (navigationContext.Parameters.ContainsKey("name"))
            {
                this.Name = navigationContext.Parameters.GetValue<string>("name");
            }
            if (navigationContext.Parameters.ContainsKey("id"))
            {
                this.Id = navigationContext.Parameters.GetValue<string>("id");
            }
        }

這裏我們判斷URL是否含有相關參數,有的話,則接收,賦值

2、進入該viewModel時,是否重新創建該viewmodle對象

        /// <summary>
        /// 進入該viewModel時,是否創建新的viewModel對象
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

3、離開viewMdoel時

        /// <summary>
        /// 離開該viewModel執行 和 路由保衛配合使用
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
             //離開時 可能會涉及到一些數據處理,在此不做演示
        }
        /// <summary>
        /// 路由保衛--可以在此方法中判斷是否允許跳轉--continuationCallback 會通知 OnNavigatedFrom 方法是否跳轉
        /// </summary>
        /// <param name="navigationContext"></param>
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            var isok = false;
            if (MessageBox.Show("確定跳轉嗎", "溫馨提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                isok = true;
            }
            continuationCallback(isok);
        }

ConfirmNavigationRequest 可以理解爲路由保衛,用於判斷是否可以跳轉, continuationCallback 爲回調函數,當它的參數爲true時,則允許跳轉,否則不跳轉。

4、雙向綁定

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                name = value;
                RaisePropertyChanged();
            }
        }
        private string id;
        public string Id
        {
            get { return this.id; }
            set
            {
                id = value;
                RaisePropertyChanged();
            }
        }

注意使用 RaisePropertyChanged();方法即可

@天才臥龍的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章