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

vbn*_*vbn 0 windows-phone mvvmcross windows-phone-8

在我的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));
Run Code Online (Sandbox Code Playgroud)

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

Stu*_*art 6

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

MvxNavigatingObject,您可以看到MvvmCross将导航调用路由到IMvxViewDispatcherWindowsPhone中的一个非常薄的对象 - 它所做的只是对所有对UI线程的调用进行编组并将它们传递给IMvxViewPresenter- 请参阅https://github.com/ MvvmCross/MvvmCross/BLOB/V3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone /浏览/ MvxPhoneViewDispatcher.cs

演示者是在Setup- 中创建的对象- 默认实现使用an IMvxPhoneViewModelRequestTranslator将导航调用转换为基于uri的导航 - 请参阅 https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross .WindowsPhone /浏览/ 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 /浏览/ MvxPhoneExtensionMethods.cs


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

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

     public class MyNavigator : MvxNavigatingObject {
          public void DoIt() {
              ShowViewModel<MyViewModel>();
          }
     }
    
     // used as:
     var m = new MyNavigator();
     m.DoIt();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以改为使用IoC来定位IMvxViewDispatcher或者IMvxViewPresenter可以Show直接调用它们的方法

     var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
     var presenter = Mvx.Resolve<IMvxViewPresenter>();
     presenter.Show(request);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您可以编写模仿其IMvxViewPresenter功能的手动代码- 与您的代码完全相同 - 尽管使用它IMvxPhoneViewModelRequestTranslator.cs来帮助生成URL 可能更"安全" - 请参阅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);
    
    Run Code Online (Sandbox Code Playgroud)

另外一个选择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);
    }
Run Code Online (Sandbox Code Playgroud)

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