是否有在Windows Phone中在屏幕之间导航的typesafe方式?
-
20-12-2019 - |
题
我正在寻找一种在我的应用程序中的屏幕之间导航的方法。基本上我到目前为止所看到的包括将字符串URI传递给NavigationService,并带有查询字符串参数。,例如
NavigationService.Navigate(new Uri("/MainPage.xaml?selectedItem=" +bookName.Id, UriKind.Relative));
虽然最终我并不热衷于这个,因为它需要魔法弦,而且它们可能会导致问题。
理想情况下,我只是创建一个我想要导航到的类的实例,将参数作为参数传递给构造函数。这可能吗?如果是这样,如何?
解决方案
虽然实际导航必须最终使用字符串,但您可以创建或使用类型安全的包装器。
我会建议看 caliburn micro 即使您只使用它为类型的安全导航。这是一个snippet 从在WP8中使用它的教程:
Toolkit附带的NavigationService支持查看模型首先方法:而不是声明,这是我们想要携带用户的页面的URL(即标准方法),我们声明是我们要显示的视图。 服务将要注意创建正确的URL并显示与视图模型相关联的视图。
或者,您可以查看 Windows Phone MVC ,也有一些类型的安全导航。您甚至可以能够将导航代码拉出以自行使用,因为它在 MS-PL < / a>。
其他提示
基本上,不,不是内置的。不幸的是,像IRepository实例这样的复杂参数超出了Silverlight中导航设施的能力;我通常使用某种形式的IoC容器来处理这些。简单的POCO参数很容易序列化为字符串,但这仍然需要魔术字符串和手动查询字符串解析。
然而,你可以很容易地自己构建一些类型安全的东西。例如,这是我的方法。
对于参数数据,我有一个我称之为'Extras'的类,它包装了一个 Dictionary<string, object>
用像这样的方法 GetBool(string)
, GetInt32(string)
, 等。,并具有静态工厂方法 CreateFromUri(Uri)
;这对我的目的来说已经足够了。
我将此与类型安全导航结合使用。我真的很喜欢MVVM模式,我的每个页面都有一个ViewModel封装了几乎所有的逻辑。Page与ViewModel的一对一关系使后者成为理想的导航键。这与属性和反射相结合,给了我们一个简单的解决方案:
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);
最后,这给出了强类型导航的外观。这是一个简单的方法;在我的脑海中,这可以通过在导航属性中添加所需的参数并在导航时验证它们来改进。它也不支持更复杂的导航类型,其中导航参数的值将决定最终的目的地。尽管如此,这适合我的90%用例-也许它也会为你工作。
这里肯定省略了一些细节,比如如何准确地获取 NavigationService
-今晚晚些时候我可以制作一个更完整的样本,但这应该足以开始。
可以使用PhoneApplicationService.State
是一个Dictionary<String,Object>
PhoneApplicationService.State
通常用于tombstoning以存储应用程序的当前状态。但是,它可以用于方便地通过页面之间的数据。
当用户导航到时,Windows Phone应用程序被取消激活 另一个申请。当用户返回应用程序时,通过 使用后退按钮或完成启动器或选择器任务, 申请重新激活。应用程序可以存储瞬态 在处理程序中的州词典中的应用状态 停用事件。在激活的事件处理程序中,应用程序可以 使用存储在状态字典中的值到瞬态应用程序 州。
基本上你会做什么是
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;
.
WPF支持导航到已创建的对象,但WP8缺少 Navigate
超负荷。
如果您不想硬编码XAML页面Uri,则可以使用以下(有点脏)帮助函数来获取。某些类的xaml资源URI。
static Uri GetComponentUri<T>() where T : DependencyObject, new() {
return BaseUriHelper.GetBaseUri(new T());
}
然后,您可以修改该URL并导航到它:
var baseUri = GetComponentUri<SomePage>(); //Uri="pack://application:,,,/MyProject;component/MainWindow.xaml"
var pageUri = new UriBuilder(baseUri) { Query = "selectedItem=" + bookName.Id };
NavigationService.Navigate(pageUri);
我们的解决方案很好:
1. 不要使用查询字符串在页面URI中,这只是完全再次查看的MVVM应该只是显示的东西,但是加载和选择项目的实际逻辑是在ViewModel中。
2.使用Const Page名称创建类,每当要导航时,只需使用:
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));
}
}
.