mvvmcross: NavigationService.Navigate выдает исключение MvxException Невозможно найти входящий запрос mvxviewmodelrequest

В моем приложении WP8 у меня есть MainView, ссылающийся на MainViewModel. MainView — это меню, в котором пользователи могут переходить к другим представлениям для выполнения некоторых задач. Навигация из MainView работает отлично, поскольку я использую ShowViewModel. Однако при переходе из других представлений, когда пользователь завершает задачу, обратно в MainView с помощью NavigationService.Navigate(URI) возникает исключение «Не удалось найти входящий запрос 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?


person vbn    schedule 09.01.2014    source источник


Ответы (1)


Большинство переходов в образцах MvvmCross инициируются либо объектами MvxAppStart, либо объектами MvxViewModel. Оба этих класса наследуются от MvxNavigatingObject и используют представленные там методы ShowViewModel — см. ">https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNavigatingObject.cs

Из MvxNavigatingObject видно, что MvvmCross направляет навигационный вызов на IMvxViewDispatcher, который в WindowsPhone является очень тонким объектом — все, что он делает, — это распределяет все вызовы по потоку пользовательского интерфейса и передает их 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 — если ее нет, он пытается найти ее, используя информацию в uri — см. https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneExtensionMethods.cs< /а>


Имея в виду это объяснение, если какое-либо приложение когда-либо захочет инициировать навигацию MvvmCross из класса, который еще не наследуется от MvxNavigatingObject - например. из какого-то Service или из какого-то другого класса, то есть несколько вариантов:

  1. Вы можете предоставить объект прокладки для навигации, например:

     public class MyNavigator : MvxNavigatingObject {
          public void DoIt() {
              ShowViewModel<MyViewModel>();
          }
     }
    
     // used as:
     var m = new MyNavigator();
     m.DoIt();
    
  2. Вместо этого вы можете использовать IoC, чтобы найти IMvxViewDispatcher или IMvxViewPresenter и напрямую вызывать их методы Show.

     var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
     var presenter = Mvx.Resolve<IMvxViewPresenter>();
     presenter.Show(request);
    
  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);
    

Еще один вариант, который всегда есть у 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 другим базовым классом, который использует собственную логику для определения местоположения модели представления. Это легко сделать в WindowsPhone, так как все XAML-страницы имеют встроенную поддержку привязки данных.

person Stuart    schedule 10.01.2014