标题有点唬人哈,其实是我自己按照平时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,提供了常用的导航方法如下:
public void GoBack();
public void NavigateTo(string pageKey);
public virtual void NavigateTo(string pageKey, object parameter);
而NavigateTo导航方法中需要提供的是string类型的参数,通过该参数与Configure属性中具体的Page映射关系来确定要导航到哪一页。打开ViewModelLocator类文件在Ioc容器中注册NavigationService对象,具体代码如下:
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//注册VM
SimpleIoc.Default.Register<MainPageViewModel>();
SimpleIoc.Default.Register<Page1ViewModel>();
SimpleIoc.Default.Register<Page2ViewModel>();
//注册导航服务对象
SimpleIoc.Default.Register(InitNavigationService);
}
/// <summary>
/// 创建NavigationService对象
/// </summary>
/// <returns>NavigationService</returns>
protected INavigationService InitNavigationService()
{
var service = new NavigationService();
service.Configure(typeof(MainPageViewModel).FullName, typeof(MainPage));
service.Configure(typeof(Page1ViewModel).FullName, typeof(Page1));
service.Configure(typeof(Page2ViewModel).FullName, typeof(Page2));
return service;
}
注册NavigationService对象和注册VM是一样的,我们通过InitNavigationService()方法来返回一个NavigationService实例对象,并在Configure中注册页面与key之间的映射,这里推荐使用typeof(MainPageViewModel).FullName的方式设置key,好处不言而喻,防止用的时候写错QAQ
添加完key/Page映射,注册完NavigationService对象后,在ViewModelLocator类中添加一个用来获取刚才注册的NavigationService对象的属性
/// <summary>
/// 导航服务器
/// </summary>
public INavigationService NavigationService => ServiceLocator.Current.GetInstance<INavigationService>();
至此,配置的工作已完成,使用的时候很简单,直接根据key去导航,如下:
//进行导航
ViewModelLocator.Default.NavigationService.NavigateTo(typeof(Page1ViewModel).FullName, "这里也可以填写参数");
虽然可以填写参数,但是不建议在此传递参数,为什么呢?因为在此传参的话,Page中就必须重写OnNavigatedTo方法来获取该参数,这样就会增加VM与View之间的耦合度。
既然使用了MvvmLight框架那么这种情况是不允许让它发生的。很简单,MvvM的设计模式的一个核心理念就是数据驱动界面,把数据的地位放到第一位,任何界面的变化都是由于数据发生了变化,而不是以前的事件驱动机制使用事件来操作数据的变化。从而MVVM中诞生了数据绑定、集合数据变更通知等一些技术。
这里推荐大家在传递数据时不妨考虑直接去修改数据,你传递过去不也是为了给一个对象赋值么?所以在这里可以给要跳转的界面的VM中的某个属性赋值,然后让UI再去绑定这个属性,属性值变化了,UI当然也会跟着变化,这就是数据驱动机制。
所以传参可以这样:
//为要跳转界面的VM 的属性赋值
ViewModelLocator.Default.Page2ViewModel.NavigateParameter = "我是参数";
ViewModelLocator.Default.NavigationService.NavigateTo(typeof(Page2ViewModel).FullName);
效果图:
本文出自:53078485群大咖Aran,欢迎您的加入!