是否有一种类型安全的方式在Windows Phone中的屏幕之间导航?

我正在寻找一种在我的应用程序中的屏幕之间导航的方法。 基本上我到目前为止看到的是将字符串URI传递给NavigationService,并使用查询字符串参数完成

NavigationService.Navigate(new Uri("/MainPage.xaml?selectedItem=" +bookName.Id, UriKind.Relative)); 

我并不是真的热衷于此,但最终因为它需要魔术弦,而且它们可能导致问题。

理想情况下,我只是创建一个我想要导航到的类的实例,将参数作为参数传递给构造函数。 这可能吗? 如果是这样,怎么样?

虽然实际导航最终必须使用字符串,但您可以创建或使用类型安全的包装器。

我建议看看Caliburn Micro,即使你只是用它来进行类型安全导航。 以下是WP8中使用它的教程的片段:

工具包附带的NavigationService支持视图模型的第一种方法:我们声明哪个是我们想要显示的ViewModel,而不是声明哪个是我们想要用户的页面的URL(这是标准方法)。 该服务将负责创建正确的URL并显示与视图模型关联的视图

或者你可以看看Windows Phone MVC ,它也有一些类型安全的导航。 您甚至可以将导航代码拉出来自行使用,因为它是在MS-PL下获得许可的。

基本上,不,不是内置的。 遗憾的是,像IRepository实例这样的复杂参数超出了Silverlight中导航function的能力。 我通常使用某种forms的IoC容器来处理这些。 更简单的POCO参数很容易序列化为字符串,但仍需要魔术字符串和手动查询字符串解析。

但是,您可以轻松地自己构建类型安全的东西。 例如,这是我的方法。

对于参数数据,我有一个我称之为’Extras’的类,它使用GetBool(string)GetInt32(string)等方法包装Dictionary ,并且具有静态工厂方法CreateFromUri(Uri) ; 这对我的目的来说足够好了。

我将它与类型安全导航结合使用。 我非常喜欢MVVM模式,我的每个页面都有一个ViewModel,它几乎封装了所有逻辑。 页面与ViewModel的一对一关系使后者成为理想的导航键。 结合属性和reflection,我们给出了一个简单的解决方案:

 public class NavigationTargetAttribute : Attribute { private readonly Type target; public ViewModelBase Target { get { return target; } } public NavigationTargetAttribute(Type target) { this.target = target; } } 

使用正确的ViewModel类型将其中一个放在每个页面上。

 [NavigationTarget(typeof(LoginViewModel))] public class LoginPage : PhoneApplicationPage { ... } 

然后,在单独的NavigationManager-esque类中,您可以执行以下操作:

 GetType().Assembly .GetTypes() .Select(t => new { Type = t, Attr = t.GetCustomAttributes(false).FirstOrDefault(attr => attr is NavigationTargetAttribute) }) .Where(t => t.Attr != null); 

就像那样,您的应用程序中包含每个可导航类型的集合。 从那里开始,将它们放入字典中的工作并不多。 如果您遵循约定放置页面的位置,您可以(例如)在类型和Uri之间轻松转换…例如, new Uri("/Pages/" + myPageType.Name + ".xaml", UriKind.Relative) 。 添加对查询参数的支持并不多。 最后,你最终会得到一个方法,如下所示:

 public void Navigate(Type target, Extras extras) { Type pageType; if (navigationTargets.TryGetValue(target, out pageType)) { var uri = CreateUri(pageType, extras); navigationService.NavigateTo(uri); } // error handling here } 

最后,在页面的OnNavigatedTo方法中,我做了类似的事情:

 var extras = Extras.CreateFromUri(e.Uri); ((ViewModelBase) DataContext).OnNavigatedTo(extras); 

最后,这给出了强类型导航的外观。 这是一个简单的方法; 通过在导航属性中添加所需参数并在导航时validation它们,可以改善这一点。 它也不支持更复杂的导航类型,其中nav参数的值将决定最终目的地。 不过,这适合我90%的用例 – 也许它也适合你。

这里肯定省略了一些细节,比如如何获得NavigationService的实例 – 我可以在今晚晚些时候处理更完整的样本,但这应该足以开始了。

您可以使用PhoneApplicationService.State

它是Dictionary

PhoneApplicationService.State通常用于逻辑删除以存储应用程序的当前状态。 但是,它可以用于方便地在页面之间传递数据。

MSDN文档

当用户导航到另一个应用程序时,Windows Phone应用程序将被停用。 当用户返回应用程序时,通过使用“后退”按钮或完成启动器或选择器任务,应用程序将重新激活。 应用程序可以在Deactivated事件的处理程序中的状态字典中存储临时应用程序状态。 在Activated事件处理程序中,应用程序可以使用存储在State字典中的值来暂时应用程序状态。

基本上你要做的是

 PhoneApplicationService.State.add(selectedName,yourobjectInstance); NavigationService.Navigate((new Uri("/MainPage.xaml?selectedItem="+selectedName,UriKind.Relative)); 

然后在您导航过的方法中,您可以检索它

 YourObject yourObjectInstance; var yourObj = PhoneApplicationService.State["yourObjectName"]; yourObjectInstance = yourObj is YourObject ? (yourObj as YourObject) : null; 

以下是对如何使用此function的更深入了解

WPF支持导航到已创建的对象,但WP8缺少Navigate重载。

如果您不想对XAML页面URI进行硬编码,则可以使用以下(有点脏)辅助函数来获取某些类的.xaml资源URI。

 static Uri GetComponentUri() where T : DependencyObject, new() { return BaseUriHelper.GetBaseUri(new T()); } 

然后,您可以修改该URL并导航到它:

 var baseUri = GetComponentUri(); //Uri="pack://application:,,,/MyProject;component/MainWindow.xaml" var pageUri = new UriBuilder(baseUri) { Query = "selectedItem=" + bookName.Id }; NavigationService.Navigate(pageUri); 

我们的解决方案很好用:
1. 不要在Page Uris中使用查询字符串 ,这完全是MVVM,其中视图应该只显示内容,但加载和选择项目的实际逻辑是在ViewModel中。
2. 使用const页面名称创建类,只要您想要导航,只需使用:

 public static class P { public const string ArticlePage = "/Pages/ArticlePage.xaml"; public const string OnlineSectionPage = "/Pages/OnlineSectionPage.xaml"; public const string GalleryPage = "/Pages/GalleryPage.xaml"; ... } // in our viewModel NavigationService.Navigate(P.ArticlePage); // In navigation service public void Navigate(string pagePath) { if (EnsureMainFrame()) { mainFrame.Navigate(new Uri(pagePath, UriKind.RelativeOrAbsolute)); } }