在我的WP8应用程序中,我有MainView引用MainViewModel。 MainView是一个菜单,用户可以在其中导航到其他视图以执行某些任务。当我使用ShowViewModel时,从MainView导航工作完美。但是,当用户完成任务时从其他视图导航,使用NavigationService.Navigate(URI)返回MainView会抛出异常“无法找到传入的mvxviewmodelrequest”。
为了避免这种异常,我构建了如下
的URIvar 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?
答案 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
或其他类中,有几个选项:
您可以提供一个填充对象来进行导航 - 例如:
public class MyNavigator : MvxNavigatingObject {
public void DoIt() {
ShowViewModel<MyViewModel>();
}
}
// used as:
var m = new MyNavigator();
m.DoIt();
您可以使用IoC找到IMvxViewDispatcher
或IMvxViewPresenter
,然后直接调用Show
种方法
var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
var presenter = Mvx.Resolve<IMvxViewPresenter>();
presenter.Show(request);
您可以编写模仿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);
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页面都具有内置的数据绑定支持。