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

时间:2011-01-15 19:10:38

标签: c# silverlight windows-phone-7 navigation

我一直在使用NavigationService的{​​{1}}方法导航到我的WP7 Silverlight应用中的其他页面:

Navigate

NavigationService.Navigate(new Uri("/Somepage.xaml?val=dreas", UriKind.Relative)); 开始,我按如下方式检索查询字符串参数:

Somepage.xaml

我现在需要一种以类似方式传递复杂对象的方法。每次我需要将对象传递给新页面时,如何才能执行而不必序列化对象

5 个答案:

答案 0 :(得分:14)

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

传递导航数据的核心问题是Tombstoning 。默认情况下逻辑删除的唯一数据是导航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属性就会调用该方法。在这种方法中,所有与业务数据有关的事情都会发生。

答案 1 :(得分:9)

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

App.MyComplexObject

或者如果不是staic

(App.Current as App).MyComplexObject;

答案 2 :(得分:5)

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

时,导航周期开始
  1. 首先 OnNavigatingFrom Page1 的事件触发
  2. 然后 Page2 构造函数触发
  3. 然后 PageN OnNavigatedFrom 事件在其EventArgs( e.Content )中创建的页面的引用触发< e.Content 强>第2页
  4. 最后 OnNavigatedTo Page2 的事件触发
  5. 因此我们在导航开始的页面中获取其他页面的引用。

    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

    中的更多调整来处理逻辑删除问题

答案 3 :(得分:1)

有争议的解决方案,如果有的话,将其作为临时解决方案。

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

public static class VarsForPages {

    // Be sure to include public static.
    public static SomeClass SomeClassObject;
    public static List<string> SomeList = new List<string>();
    public static string SomeData = "SomeValue";

}

// The syntax for referencing the data
   VarsForPages.SomeClassObject; 
   VarsForPages.SomeList; 
   VarsForPages.SomeData;

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

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

答案 4 :(得分:1)

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

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

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

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

在通话类中:

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