在WP7 Silverlight应用程序中导航时将复杂对象传递给页面

我一直在使用NavigationServiceNavigate方法导航到我的WP7 Silverlight应用程序中的其他页面:

 NavigationService.Navigate(new Uri("/Somepage.xaml?val=dreas", UriKind.Relative)); 

Somepage.xaml ,然后我检索查询字符串参数,如下所示:

 string val; NavigationContext.QueryString.TryGetValue("val", out val); 

我现在需要一种使用类似方式传递复杂对象的方法 。 如何每次需要将对象传递到新页面时序列化对象时如何执行此操作?

这是一个非常复杂的问题,这里没有简单的解决方案。 没有神奇的API可以适用于任何应用程序来解决这个问题。

传递导航数据的核心问题是墓碑 。 默认情况下,逻辑删除的唯一数据是导航URI。 因此,如果您使用的是QueryString参数,它将通过逻辑删除和您的代码自动获取。 任何时候你手动传递一个对象的实例,你必须自己手动为该实例进行逻辑删除。

因此,如果您导航到“/CowDetails.xaml?ID=1”,您的页面可能只需要通过ID查询字符串参数就可以获得完美的逻辑删除。 但是,如果你以某种方式为CowDetails页面提供了“new Cow(){ID = 1}”,那么你必须自己确保墓碑和zombificate这个值。

此外,还有时间问题 。 在调用NavigationService.Navigate时,您正在导航的页面也没有实际的实例。 因此,即使您正在导航到FooPage并准备好FooData,也无法立即将FooPage连接到FooData。 您必须等到PhoneApplicationFrame.Navigated事件被触发才能为FooPage提供FooData。

我通常处理这个问题的方法是:

  1. 具有对象类型数据属性的BasePage
  2. 让NavigationHelper获取页面URI和数据:NavigationHelper.Navigate(“foo.xaml”,fooData)
  3. 让NavigationHelper注册到PhoneApplicationFrame.Navigated事件,如果它是“foo.xaml”,则将BasePage.Data设置为FooData。
  4. 让BasePage使用JSON.Net到tombstone和zombificate BasePage.Data。
  5. 在BasePage上,我有一个OnDataSet虚拟方法,一旦通过Zombification或Navigation填充Data属性就会调用它。 在这种方法中,发生了与业务数据有关的所有事情。

App.xaml.cs – > App类,在那里添加一个字段/属性。 要访问它,如果是静态使用:

 App.MyComplexObject 

或者如果不是staic

 (App.Current as App).MyComplexObject; 

有一个非常简单的解决方案来解决这个问题。 请考虑以下示例Windows Phone应用程序有以下两个页面, Page1.xamlPage2.xaml让我们从Page1.xaml说我们正在导航到Page2.xaml 。 当您调用NavigationService.Navigate方法时,导航循环开始

  1. 第一次OnNavigatingFrom Page1事件发生
  2. 然后Page2的 构造函数触发
  3. 然后OnNavigatedFrom Page1的事件触发其EventArgs中创建的页面的引用( e.Content具有创建的Page2实例)
  4. 最后OnNavigatedTo Page2事件发生了

因此,我们在导航开始的页面中获取其他页面的引用。

 public class PhoneApplicationBasePage : PhoneApplicationPage { private object navParam = null; protected object Parameter{get;private set;} //use this function to start the navigation and send the object that you want to pass //to the next page protected void Navigate(string url, object paramter = null) { navParam = paramter; this.NavigationService.Navigate(new Uri(url, UriKind.Relative)); } protected override void OnNavigatedFrom(NavigationEventArgs e) { //e.Content has the reference of the next created page if (e.Content is PhoneApplicationBasePage ) { PhoneApplicationBasePage page = e.Content as PhoneApplicationBasePage; if (page != null) { page.SendParameter(navParam); navParam=null;} } } private void SendParameter(object param) { if (this.Parameter == null) { this.Parameter = param; this.OnParameterReceived(); } } protected virtual void OnParameterReceived() { //Override this method in you page. and access the **Parameter** property that // has the object sent from previous page } } 

所以在我们的Page1.xaml.cs中,我们只需调用Navigate("/Page2.xaml",myComplexObject) 。 在你的Page2.xaml.cs中,我们将覆盖OnParameterReceived方法

  protected override void OnParameterReceived() { var myComplexObjext = this.Parameter; } 

而且,通过PhoneApplicationBasePage中的更多调整,也可以处理逻辑删除问题

有争议的解决方案,如果有的话,使它成为临时的

在应用程序的命名空间下创建此项,以用于必要的页面。

 public static class VarsForPages { // Be sure to include public static. public static SomeClass SomeClassObject; public static List SomeList = new List(); public static string SomeData = "SomeValue"; } // The syntax for referencing the data VarsForPages.SomeClassObject; VarsForPages.SomeList; VarsForPages.SomeData; 

现在,您可以在应用程序的任何位置引用SomeClassObject,SomeList,SomeData。

注意:与任何全局数据一样,要对可能对全局数据进行的许多访问和修改感到厌倦。 我这样说,因为我曾经有一个列表增加的大小,但我的应用程序中的一个页面依赖于列表的大小有一些价值,这导致了一个错误。 不要忘记,数据是全球性的。

我希望我能回复vjsrinath上面的回复; IMO是实现这一目标的最佳方式。 非常感谢!!

这可能是我见过的最接近iOS模型的工作方式,从第一页调用performSegue(== NavigateTo)。 然后你得到一个名为prepareForSegue的回调,它允许你在目标页面中设置变量,设置委托(通常是自己),那种东西。

对于复杂的对象传递,它会在URL中传递params。

作为一个明确的例子,假设我想将我的应用程序的版本字符串传递给一个单独项目中的About框:

在调用类中:

 private void About_Click(object sender, EventArgs e) { NavigationService.Navigate(new Uri("/Library;component/Pages/About.xaml", UriKind.Relative)); } protected override void OnNavigatedFrom(NavigationEventArgs e) { if (e.Content is About) { About page = e.Content as About; if (page != null) { page.VersionString = App.VersionText; } } base.OnNavigatedFrom(e); } 

在About类中:

 public partial class About : PhoneApplicationPage { public string VersionString { get; set; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); versionTextBlock.Text = VersionString; } } 

这当然是一个非常简单的例子,但是你经过的属性可能是任何对象,这使得它非常强大。 当然它可以包括回调,例如“saveButtonPressed”等,因此保存处理可以在调用类中完成,而不是呈现的视图,这对于代码整洁而言非常糟糕。 例如,

 page.OnSaveButtonPressed = this.SaveButtonPressedHandler; // Pass object to save as parameter