MvvmLigth框架利器之INavigationService

标题有点唬人哈,其实是我自己按照平时UWP/WP项目开发的使用经验给INavigationService加封的,由于网络中关于Mvvmlight框架的INavigationService的资料比较少,所以在此做个笔记,一来记录知识以防忘记,二来希望对用到INavigationService的朋友有所帮助。

Mvvmlight在平时开发中最常用到的利器有五个:
    1.ViewModelBase VM鼻祖
    2.RelayCommand命令
    3. Messenger消息通知
    4.DispatcherHelper 多线程处理
    5.INavigationService导航服务

ViewModelBase VM基类,里面提供了VM中常用的方法。

RelayCommand命令,这东西在UWP出来之前使用率是很高的,UI上的Command绑定VM方法是必须用到RelayCommand,用来解耦很是方便实用,不过UWP中基本就用不到它了,UWP中的UI事件可以直接绑定到方法名,RelayCommand便从此可以在UWP项目代码中退隐江湖了。

Messenger消息通知,这个谁用谁知道,不过建议大家用的时候仔细考虑下要做的Action是否超出了VM本身的职责,不然不要滥用,不然项目逻辑太过于分散。Messenger的设计初衷就是用来使VM与View能够相互通信,VM告诉View我事情做完了接下来你要接着做你的事情,这种情况下才适合使用Messenger,千万不要在VM内部滥用Messenger。

DispatcherHelper多线程处理,这个用来帮助我们在非UI线程上处理UI线程对象的帮助类,也非常好用。

前四个本文章内不做过多的讲解,本文的主要内容是INavigationService的使用。

INavigationService导航服务,这家伙是为了项目解耦、平台自适应而诞生的。它的作用主要是用来导航界面(这不是废话么),但最重要的是它能在VM中直接发起导航界面来完成导航。让导航脱离具体的Page对象,减少了VM与View的耦合,而且还不受平台的限制,使用它进行导航,即使平台之间各自导航的方法各异,也完全不受影响。

好处都说了多么多,那具体该怎么使用呢?想要使用INavigationService需要先在SimpleIoc.Default中注册一个NavigationService对象,NavigationService对象继承与INavigationService,提供了常用的导航方法如下: 

  1. public void GoBack();
  2. public void NavigateTo(string pageKey);
  3. public virtual void NavigateTo(string pageKey, object parameter);
复制代码


而NavigateTo导航方法中需要提供的是string类型的参数,通过该参数与Configure属性中具体的Page映射关系来确定要导航到哪一页。

打开ViewModelLocator类文件在Ioc容器中注册NavigationService对象,具体代码如下: 

  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.     //注册VM
  5.     SimpleIoc.Default.Register<MainPageViewModel>();
  6.     SimpleIoc.Default.Register<Page1ViewModel>();
  7.     SimpleIoc.Default.Register<Page2ViewModel>();
  8.     //注册导航服务对象
  9.     SimpleIoc.Default.Register(InitNavigationService);
  10. }
  11. /// <summary>
  12. /// 创建NavigationService对象
  13. /// </summary>
  14. /// <returns>NavigationService</returns>
  15. protected INavigationService InitNavigationService()
  16. {
  17.     var service = new NavigationService();
  18.     service.Configure(typeof(MainPageViewModel).FullName, typeof(MainPage));
  19.     service.Configure(typeof(Page1ViewModel).FullName, typeof(Page1));
  20.     service.Configure(typeof(Page2ViewModel).FullName, typeof(Page2));
  21.     return service;
  22. }
复制代码


注册NavigationService对象和注册VM是一样的,我们通过InitNavigationService()方法来返回一个NavigationService实例对象,并在Configure中注册页面与key之间的映射,这里推荐使用typeof(MainPageViewModel).FullName的方式设置key,好处不言而喻,防止用的时候写错QAQ 

添加完key/Page映射,注册完NavigationService对象后,在ViewModelLocator类中添加一个用来获取刚才注册的NavigationService对象的属性

  1. /// <summary>
  2. /// 导航服务器
  3. /// </summary>
  4. public INavigationService NavigationService => ServiceLocator.Current.GetInstance<INavigationService>();
复制代码


至此,配置的工作已完成,使用的时候很简单,直接根据key去导航,如下: 

  1. //进行导航
  2. ViewModelLocator.Default.NavigationService.NavigateTo(typeof(Page1ViewModel).FullName, "这里也可以填写参数");
复制代码


虽然可以填写参数,但是不建议在此传递参数,为什么呢?因为在此传参的话,Page中就必须重写OnNavigatedTo方法来获取该参数,这样就会增加VM与View之间的耦合度。

既然使用了MvvmLight框架那么这种情况是不允许让它发生的。很简单,MvvM的设计模式的一个核心理念就是数据驱动界面,把数据的地位放到第一位,任何界面的变化都是由于数据发生了变化,而不是以前的事件驱动机制使用事件来操作数据的变化。从而MVVM中诞生了数据绑定、集合数据变更通知等一些技术。

这里推荐大家在传递数据时不妨考虑直接去修改数据,你传递过去不也是为了给一个对象赋值么?所以在这里可以给要跳转的界面的VM中的某个属性赋值,然后让UI再去绑定这个属性,属性值变化了,UI当然也会跟着变化,这就是数据驱动机制。

所以传参可以这样: 

  1. //为要跳转界面的VM 的属性赋值
  2. ViewModelLocator.Default.Page2ViewModel.NavigateParameter = "我是参数";
  3. ViewModelLocator.Default.NavigationService.NavigateTo(typeof(Page2ViewModel).FullName);
复制代码


效果图: 
<ignore_js_op> 

本文出自:53078485群大咖Aran

posted @ 2016-10-15 16:27  天涯海角路  阅读(425)  评论(0)    收藏  举报