豆瓣电台WP7客户端 MVVM重构记录之使用MVVM Light的Message实现导航

这几天使用MVVM重构这个应用,发现一个严重的问题,那就是导航。基于MVVM的思想,View跟ViewModel之间依靠绑定等技术通信,而且是View可以拿到ViewModel,ViewModel不可以拿到View。本来用CodeBehind的时候很容易的导航,到这里就无从下手了。当然也是有办法把View传递到ViewModel的,不过这样就破坏了MVVM的初衷了。

解决这个问题,首先需要解决怎么在ViewModel中得到NavgationServices来导航。以下是解决办法:

root = Application.Current.RootVisual as PhoneApplicationFrame;

拿到这个root之后就可以导航了。

root.Navigate(pageUri);
MVVM Light的Message机制可以Send一个消息,它会被广播出去,然后被register的对象接收,然后调用指定的方法。
思路:
当一个VM需要导航的时候,Send一个Message把导航的URL传递出去,这个消息被一个NavgationController截获,执行导航操作,导航完成之后NavgationController会Send一个Message,通知导航到的View对应的ViewModel执行Navigated方法。
 
 
 
using System;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Phone.Controls;
using GalaSoft.MvvmLight.Messaging;
namespace MvvmLightNavgation
{
    public class NavigationHelper 
    {
        private static PhoneApplicationFrame root;
         
        public static PhoneApplicationFrame GetPhoneFrameRoot()
        {
        
         if (root == null)
          {
            root = Application.Current.RootVisual as PhoneApplicationFrame;
           if (root == null)
            {
           throw new Exception("获取 ApplicationRootVisual 失败!");
            }
           }
		return root;
} /// <summary> /// 根据url字符串导航 /// </summary> /// <param name="url"></param> public static void NavigationTo( string url) { if (root== null) GetPhoneFrameRoot(); if(root != null) { var pageUri = new Uri(url, UriKind.Relative); root.Navigate(pageUri); } } /// <summary> /// 根据Uri导航 /// </summary> /// <param name="pageUri"></param> public static void NavigationTo( Uri pageUri) { if (root == null) GetPhoneFrameRoot(); if (root != null) { root.Navigate(pageUri); } } public static Uri CreateUri( string url) { return new Uri(url, UriKind.RelativeOrAbsolute); } /// <summary> /// 发送导航Msg /// </summary> /// <param name="pageUri"></param> public static void NavigationMsgSend( Uri pageUri) { Messenger.Default.Send(pageUri, MsgToken.Navigation); } /// <summary> /// 发送导航Msg /// </summary> /// <param name="pageUrl"></param> public static void NavigationMsgSend( string pageUrl) { Messenger.Default.Send(CreateUri(pageUrl), MsgToken.Navigation); } /// <summary> /// 注册导航完成MSG /// </summary> public static void NavigatedMsgReg( object recipient) { INavigation navigation = recipient as INavigation; if (navigation!= null) { Messenger.Default.Register< Uri>(recipient, navigation.GetViewUrl(), navigation.Navigated); } } } }

这个类提供了一堆静态方法来实现页面之间的导航。其中最重要的方法是:

/// <summary>
      /// 发送导航Msg
      /// </summary>
      /// <param name="pageUrl"></param>
      public static void NavigationMsgSend(string pageUrl)
      {
          Messenger.Default.Send(CreateUri(pageUrl), MsgToken.Navigation);
      }

      /// <summary>
      /// 注册导航完成MSG
      /// </summary>
      public static  void NavigatedMsgReg(object recipient)
      {
          INavigation navigation = recipient as INavigation;
          if (navigation!=null)
          {
              Messenger.Default.Register<Uri>(recipient, navigation.GetViewUrl(), navigation.Navigated);
          }
      }
     
 
 

NavigationController :

using GalaSoft.MvvmLight.Messaging;
namespace MvvmLightNavgation
{
    public class NavigationController
    {
        public NavigationController()
        {
            Messenger.Default.Register<Uri>(this, MsgToken.Navigation, Navigation);
            NavigationHelper.GetPhoneFrameRoot().Navigated += new System.Windows.Navigation.NavigatedEventHandler(RootNavigated);
        }

        private void Navigation(Uri uri)
        {
            NavigationHelper.NavigationTo(uri);
        }
     private void RootNavigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
      {
         string token = e.Uri.OriginalString;
         if (token.Contains("?"))
        {
           int index = e.Uri.OriginalString.IndexOf('?');
           token = token.Substring(0, index);
        }
        Messenger.Default.Send(e.Uri,token);
     }
 
 
    }
}

导航控制器,拦截所有导航的消息,然后导航,导航完成之后发送消息通知导航到的View对应的VM执行Navigated方法。

 

导航接口:

namespace MvvmLightNavgation
{
    public interface INavigation
    {
        /// <summary>
        /// 获取对应的View的Url
        /// </summary>
        /// <returns></returns>
        string GetViewUrl();
        /// <summary>
        /// 导航完成后发生
        /// </summary>
        /// <param name="uri"></param>
        void Navigated(Uri uri);
    }
}
让VM去实现这个接口,保证所有VM都具有这2个方法。
 

使用:

在App.xaml里添加一个NavigationController静态资源

  <Application.Resources>
        <vm:MvvmViewModelLocator xmlns:vm="clr-namespace:DBFM7"
                                   x:Key="Locator" />
        <nav:NavigationController  x:Key="NavCtr"/>
    </Application.Resources>

在需要导航的地方发送导航消息:

string pageUrl = "/View/MainPage.xaml?Channle=" + hubTitle;
NavigationHelper.NavigationMsgSend(pageUrl);
public ChannelTileViewModel()
     {
         NavigationHelper.NavigatedMsgReg(this);

        }

VM去实现导航接口:

public class ChannelTileViewModel : ViewModelBase,INavigation
   {
。。。。。。。。。。。。。。。。。。。
       /// <summary>
       /// 导航完成后发生
       /// </summary>
       /// <param name="uri"></param>
       public void Navigated(Uri uri)
       {
       }

       /// <summary>
       /// 获取对应的View的Url
       /// </summary>
       /// <returns></returns>
       public string GetViewUrl()
       {
           return "/View/ChannelTile.xaml";
       }
   }
 

转载于:https://www.cnblogs.com/kklldog/archive/2012/03/01/2374927.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值