mvvmcross:NavigationService.Navigate抛出一个MvxException“无法找到传入的mvxviewmodelrequest”

时间:2014-01-09 23:01:42

标签: windows-phone-8 windows-phone mvvmcross

在我的WP8应用程序中,我有MainView引用MainViewModel。 MainView是一个菜单,用户可以在其中导航到其他视图以执行某些任务。当我使用ShowViewModel时,从MainView导航工作完美。但是,当用户完成任务时从其他视图导航,使用NavigationService.Navigate(URI)返回MainView会抛出异常“无法找到传入的mvxviewmodelrequest”。

为了避免这种异常,我构建了如下

的URI
var req = "{\"ViewModelType\":\"MyApp.Core.ViewModels.MainViewModel, MyApp.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\",\"ClearTop\":\"true\",\"ParameterValues\":null,\"RequestedBy\":null}";
NavigationService.Navigate(new Uri("/MainView.xaml?ApplicationUrl=" + Uri.EscapeDataString(req), UriKind.Relative));

有没有人有更好的方法来使用NavigationService.Navigate?

1 个答案:

答案 0 :(得分:6)

MvvmCross示例中的大多数导航都是由MvxAppStart个对象或MvxViewModel启动的。这两个类都继承自MvxNavigatingObject并使用那里公开的ShowViewModel方法 - 请参阅https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNavigatingObject.cs

MvxNavigatingObject,您可以看到MvvmCross将导航调用路由到IMvxViewDispatcher,在WindowsPhone中这是一个非常瘦的对象 - 它所做的就是对所有对UI线程的调用进行编组并传递它们转到IMvxViewPresenter - 请参阅https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneViewDispatcher.cs

演示者是在Setup中创建的对象 - 默认实现使用IMvxPhoneViewModelRequestTranslator将导航调用转换为基于uri的导航 - 请参阅https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneViewPresenter.cs

Silverlight / WindowsPhone然后使用此uri进行导航,创建必要的Xaml页面,然后在此页面上调用OnNavigatedTo。作为base.OnNavigatedTo();处理MvxPhonePage的一部分,MvvmCross会调用OnViewCreated扩展方法。此方法检查是否已存在ViewModel - 如果没有ViewModel,则它会尝试使用uri中的信息找到一个ViewModel - 请参阅https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneExtensionMethods.cs


考虑到这个解释,如果任何应用程序想要从尚未从MvxNavigatingObject继承的类启动MvvmCross导航 - 例如从某些Service或其他类中,有几个选项:

  1. 您可以提供一个填充对象来进行导航 - 例如:

     public class MyNavigator : MvxNavigatingObject {
          public void DoIt() {
              ShowViewModel<MyViewModel>();
          }
     }
    
     // used as:
     var m = new MyNavigator();
     m.DoIt();
    
  2. 您可以使用IoC找到IMvxViewDispatcherIMvxViewPresenter,然后直接调用Show种方法

     var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
     var presenter = Mvx.Resolve<IMvxViewPresenter>();
     presenter.Show(request);
    
  3. 您可以编写模仿IMvxViewPresenter所做内容的手动代码 - 与您的代码完全相同 - 尽管使用IMvxPhoneViewModelRequestTranslator.cs协助生成代码可能更“安全”网址 - 请参阅https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/IMvxPhoneViewModelRequestTranslator.cs

     var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
     var translator = Mvx.Resolve<IMvxPhoneViewModelRequestTranslator>();
     var uri = translator.GetXamlUriFor(request);
    

  4. View始终拥有的另一个选项是,他们不必使用标准的MvvmCross导航和ViewModel位置。在WindowsPhone中,您的代码可以使用您自己的逻辑直接设置ViewModel,如:

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (ViewModel == null) {
               ViewModel = // something I locate
            }
    
            // if you are doing your own logic then `base.OnNavigatedTo` isn't really needed in winphone
            // but I always call it anyway
            base.OnNavigatedTo(e);
        }
    

    或者在WindowsPhone中,您甚至可以用不同的基类替换MvxPhonePage,该基类使用它自己的viewmodel位置逻辑。这在WindowsPhone中很容易实现,因为所有Xaml页面都具有内置的数据绑定支持。