从Windows Phone 8.1通用应用程序中的View Model导航到新页面
我正在开发一个Windows Phone 8.1通用应用程序,并希望找到处理页面导航的最佳方法,而不会在后面的代码中使用大量逻辑。 我希望尽可能整洁地将代码保留在我的视图中。 为响应按钮点击,导航到新页面的MVVM方式是什么?
我目前必须从ViewModel向视图发送一条RelayComnmand消息,其中包含要导航到的页面的详细信息。 这意味着后面的代码必须按如下方式连接:
public MainPage() { InitializeComponent(); Messenger.Default.Register(this, (article) => ReceiveOpenArticleMessage(article)); ... } private object ReceiveOpenArticleMessage(OpenArticleMessage article) { Frame.Navigate(typeof(ArticleView)); }
虽然这确实有效,但这似乎并不是最好的方法。 如何直接从ViewModel进行页面导航? 我在我的项目中使用MVVM-Light。
好的,我找到了这个问题的答案。 进行了一些调查,但我最终找到了首选的MVVM-Light方式。 无论如何我都不赞成这个答案,只是将其发布在这里以防人们正在寻找这个问题的答案。
创建一个INavigationService接口,如下所示:
public interface INavigationService { void Navigate(Type sourcePageType); void Navigate(Type sourcePageType, object parameter); void GoBack(); }
创建一个NavigationService类,如下所示:
public class NavigationService : INavigationService { public void Navigate(Type sourcePageType) { ((Frame)Window.Current.Content).Navigate(sourcePageType); } public void Navigate(Type sourcePageType, object parameter) { ((Frame)Window.Current.Content).Navigate(sourcePageType, parameter); } public void GoBack() { ((Frame)Window.Current.Content).GoBack(); } }
现在在ViewModelLocator中,将其设置如下:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] public MainViewModel Main { get { return ServiceLocator.Current.GetInstance(); } } static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register(); } else { SimpleIoc.Default.Register(() => new NavigationService()); } SimpleIoc.Default.Register(); }
接下来设置导航服务的设计时间如下:
public class DesignNavigationService : INavigationService { // This class doesn't perform navigation, in order // to avoid issues in the designer at design time. public void Navigate(Type sourcePageType) { } public void Navigate(Type sourcePageType, object parameter) { } public void GoBack() { } }
我的MainViewModel构造函数如下:
public MainViewModel(INavigationService navigationService) { _navigationService = navigationService; ...
现在您可以使用它在viewmodel中导航:
_navigationService.Navigate(typeof(WelcomeView));
有关原作者Laurent Bugnion的更多详细信息,请参阅此文章和相关代码。 http://msdn.microsoft.com/en-us/magazine/jj651572.aspx
这里有一个新的更简单的实现: https : //marcominerva.wordpress.com/2014/10/10/navigationservice-in-mvvm-light-v5/
首先我们创建NavigationService
和DialogService
(用于页面导航参数):
public ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); var navigationService = this.CreateNavigationService(); SimpleIoc.Default.Register(() => navigationService); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); } private INavigationService CreateNavigationService() { var navigationService = new NavigationService(); navigationService.Configure("Details", typeof(DetailsPage)); // navigationService.Configure("key1", typeof(OtherPage1)); // navigationService.Configure("key2", typeof(OtherPage2)); return navigationService; }
然后我们在ViewModel
创建一个RelayCommand
和NavigationService
,如下所示:
public class MainViewModel : ViewModelBase { private INavigationService _navigationService; public RelayCommand> DetailsCommand { get; set; } public MainViewModel(INavigationService navigationService) { this._navigationService = navigationService; DetailsCommand = new RelayCommand>((args) => NavigateTo(args)); } public void NavigateTo(Tuple args) { this._navigationService.NavigateTo(args.Item1, args.Item1); } public void ClickAndNavigate() { NavigateTo(new Tuple("AdminPivotPage", "Test Params")); } }
最后,我们可以像这样得到页面导航参数:
public sealed partial class DetailsPage : Page { // ... protected override void OnNavigatedTo(NavigationEventArgs e) { var parameter = e.Parameter as string; // "My data" base.OnNavigatedTo(e); } }
但是要阅读MVVM模式中页面导航中传递的参数,您可以在这里查看 。
我同意上面的ricochete ,它更简单,虽然我的直接暗示搞砸了我在Blend中的Design Data Binding。
我决定创建一个inheritance自NavigationService的类
public class NavigationServiceHelper : NavigationService { public NavigationServiceHelper() { this.Configure("Page1", typeof(View.Page1)); this.Configure("Page2", typeof(View.Page2)); } }
然后在ViewModelLocator中我以这种方式注册了它
SimpleIoc.Default.Register();
我的设计视图数据绑定再次起作用。 如果有人能够解释为什么设计数据不能用于上面的弹性模板,请做。 谢谢!