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();方法即可

@天才卧龙的博客

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