05Prism WPF 入门实战 - Navigation

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了05Prism WPF 入门实战 - Navigation相关的知识,希望对你有一定的参考价值。

1.概要

源码及PPT地址:https://github.com/JusterZhu/wemail

视频地址:https://www.bilibili.com/video/BV1KQ4y1C7tg?share\\source=copy\\web

本章分为以下三个部分来了解:

Part1 视图导航、参数传递

Part2 确认导航

Part3 导航日志

2.详细内容

Part1 视图导航、参数传递

当用户与丰富的客户端应用程序交互时,其用户界面 (UI) 将不断更新,以反映用户正在处理的当前任务和数据。随着时间的推移,随着用户与应用程序内的交互并完成各种任务,UI 可能会发生相当大的变化。应用程序协调这些 UI 更改的过程通常称为导航,这一过程由INavigationAware做支撑。

应用场景:View之间传值、需要在导航过程做操作(例如及时释放资源)。

public class ContactViewModel : BindableBase , INavigationAware
    {
        private ObservableCollection<string> _contacts;

        private string _message;
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }

        public ObservableCollection<string> Contacts 
        { 
            get => _contacts ?? (_contacts = new ObservableCollection<string>()); 
        }

        public ContactViewModel()
        {
            Message = "Wemail.Contact Prism Module";
            Contacts.Add("联系人张某");
            Contacts.Add("联系人王某");
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            var parameter = navigationContext.Parameters["Contact"];

            if (parameter == null) return;
            //导航到当前页面前, 此处可以传递过来的参数以及是否允许导航等动作的控制
            Debug.WriteLine(parameter.ToString() + "To Contact View.");
        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            //根据业务需要调整该视图,是否创建新示例。为true的时候表示不创建新实例,页面还是之前的;
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            //导航离开当前页面前。
            Debug.WriteLine("Leave Contact View.");
        }
    }

Part2 确认导航

您经常会发现您需要在导航操作期间与用户进行交互,以便用户可以确认或取消它。例如,在许多应用程序中,用户可能会尝试在输入或编辑数据时进行导航。在这些情况下,您可能需要询问用户是否希望保存或丢弃在继续从页面中导航之前已输入的数据,或者用户是否希望完全取消导航操作。这些特性由IConfirmNavigationRequest做支撑,它融入了AOP(面向切面编程)的思想。

应用场景:权限管理、检测用户行为(页面停留多久、哪个模块访问次数最多等)、日志记录等。

public class TempViewAViewModel : IConfirmNavigationRequest
    {
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            bool result = true;

            // this is demo code only and not suitable for production. It is generally
            // poor practice to reference your UI in the view model. Use the Prism
            // IDialogService to help with this.
            if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No)
                result = false;

            continuationCallback(result);
        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            //是否创建新示例。为true的时候表示不创建新示例,页面还是之前的;如果为false,则创建新的页面。
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            //导航离开当前页面前。
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            //导航到当前页面前, 此处可以传递过来的参数以及是否允许导航等动作的控制。
        }
    }

Part3 导航日志

导航日志其实就是对导航系统的一个管理功能,理论上来说,我们应该知道我们上一步导航的位置、以及下一步导航的位置,包括我们导航的历史记录。以便于我们使用导航对应用程序可以灵活的控制。类似于我们熟知的双向链表结构。导航日志由IRegionNavigationJournal提供支撑。

IRegionNavigationJournal接口有如下功能:

GoBack() : 返回上一页

CanGoBack: 是否可以返回上一页

GoForward(): 返回后一页

CanGoForward: 是否可以返回后一页

public class MainWindowViewModel : BindableBase
    {
        private string _title = "Prism Application";

        //Region管理对象
        private IRegionManager _regionManager;
        private IModuleCatalog _moduleCatalog;
        private ObservableCollection<IModuleInfo> _modules;
        private DelegateCommand _loadModulesCommand;
        private DelegateCommand _openViewA;
        private DelegateCommand _openViewB;
        private DelegateCommand _goBackView;
        private DelegateCommand _goForwardView;
        private IModuleInfo _moduleInfo;

        //导航日志
        private IRegionNavigationJournal _navigationJournal;

        public IView View { get; set; }

        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        public ObservableCollection<IModuleInfo> Modules
        {
            get => _modules ?? (_modules = new ObservableCollection<IModuleInfo>());
        }

        public DelegateCommand LoadModulesCommand { get => _loadModulesCommand = new DelegateCommand(InitModules); }

        public IModuleInfo ModuleInfo 
        { 
            get 
            {
                return _moduleInfo; 
            }

            set 
            {
                _moduleInfo = value;
                Navigate(value);
            }
        }

        public DelegateCommand OpenViewA 
        { 
            get => _openViewA ?? (_openViewA = new DelegateCommand(OpenViewAAction));
        }

        public DelegateCommand OpenViewB
        {
            get => _openViewB ?? (_openViewB = new DelegateCommand(OpenViewBAction)); 
        }

        public DelegateCommand GoBackView { get => _goBackView ?? (_goBackView = new DelegateCommand(GoBackViewAction)); }

        public DelegateCommand GoForwardView { get => _goForwardView ?? (_goForwardView = new DelegateCommand(GoForwardViewAction)); }

        public MainWindowViewModel(IRegionManager regionManager, IModuleCatalog moduleCatalog)
        {
            _regionManager = regionManager;
            _moduleCatalog = moduleCatalog;
        }

        private void OpenViewAAction()
        {
            //_regionManager.RequestNavigate("ContentRegion", "TempViewA");

            _regionManager.RequestNavigate("ContentRegion", "TempViewA",arg=> 
            {
                //记录导航日志上下文
                _navigationJournal = arg.Context.NavigationService.Journal;
            });
        }

        private void OpenViewBAction()
        {
            //_regionManager.RequestNavigate("ContentRegion", "TempViewB");

            _regionManager.RequestNavigate("ContentRegion", "TempViewB", arg =>
            {
                //记录导航日志上下文
                _navigationJournal = arg.Context.NavigationService.Journal;
            });
        }

        /// <summary>
        /// 导航日志:导航到上一个
        /// </summary>
        private void GoBackViewAction()
        {
            if (_navigationJournal.CanGoBack)
            {
                _navigationJournal.GoBack();
            }
        }

        /// <summary>
        /// 导航日志:导航到下一个
        /// </summary>
        private void GoForwardViewAction()
        {
            if (_navigationJournal.CanGoForward)
            {
                _navigationJournal.GoForward();
            }
        }

        public void InitModules() 
        {
            var dirModuleCatalog = _moduleCatalog as DirectoryModuleCatalog;
            Modules.AddRange(dirModuleCatalog.Modules);
        }

        private void Navigate(IModuleInfo info) 
        {
            var paramete = new NavigationParameters();
            //任意定义key,value。导航到的视图按照约定key获取value即可。
            paramete.Add($"{ info.ModuleName }", DateTime.Now.ToString());
            _regionManager.RequestNavigate("ContentRegion", $"{ info.ModuleName }View", paramete);
        }
    }

以上是关于05Prism WPF 入门实战 - Navigation的主要内容,如果未能解决你的问题,请参考以下文章

01Prism WPF 入门实战 - 项目准备

04Prism WPF 入门实战 - Module

03Prism WPF 入门实战 - Region

06Prism WPF 入门实战 - Log&控件库

WPF PRISM开发入门一

七从GitHub浏览Prism示例代码的方式入门WPF下的Prism之RegionContext