C# 在WP7 Silverlight应用程序中导航时向页面传递复杂对象

C# 在WP7 Silverlight应用程序中导航时向页面传递复杂对象,c#,silverlight,windows-phone-7,navigation,C#,Silverlight,Windows Phone 7,Navigation,我一直在使用NavigationService的Navigate方法导航到我的WP7 Silverlight应用程序中的其他页面: NavigationService.Navigate(new Uri("/Somepage.xaml?val=dreas", UriKind.Relative)); 然后,我从Somepage.xaml检索查询字符串参数,如下所示: string val; NavigationContext.QueryString.TryGetValue("val", out v

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

NavigationService.Navigate(new Uri("/Somepage.xaml?val=dreas", UriKind.Relative));
然后,我从
Somepage.xaml
检索查询字符串参数,如下所示:

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


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

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

App.MyComplexObject
如果不是staic

(App.Current as App).MyComplexObject;

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

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

因此,如果导航到“/CowDetails.xaml?ID=1”,只需选择ID Querystring参数,您的页面就可能具有完美的墓碑。但是,如果您以某种方式为CowDetails页面提供了一个“new Cow(){ID=1}”,那么您必须确保自己将该值墓碑化和僵尸化

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

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

  • 具有具有对象类型数据属性的BasePage
  • 让NavigationHelper获取页面URI和数据:NavigationHelper.Navigate(“foo.xaml”,fooData)
  • 让NavigationHelper注册到PhoneApplicationFrame.Navigated事件,如果是“foo.xaml”,则将BasePage.Data设置为FooData
  • 让BasePage使用JSON.Net对BasePage.Data进行逻辑删除和僵化
  • 在BasePage上,我有一个OnDataSet虚拟方法,一旦数据属性被僵尸化或导航填充,就会调用该方法。在这种方法中,与业务数据有关的一切都会发生
    有争议的解决方案,如果有的话,让它成为暂时的

    在应用程序的命名空间下为任何需要的页面创建该名称

    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;
    
    公共静态类varsforpage{
    //确保包含公共静态文件。
    公共静态SomeClass SomeClassObject;
    public static List SomeList=new List();
    公共静态字符串SomeData=“SomeValue”;
    }
    //用于引用数据的语法
    VarsForPages.SomeClassObject;
    VarsForPages.SomeList;
    VarsForPages.SomeData;
    
    现在,您可以在应用程序中的任何位置引用SomeClassObject、SomeList和SomeData


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

    解决这个问题有一个非常简单的方法。考虑下面的例子 windows phone应用程序有以下两个页面,Page1.xamlPage2.xaml 假设我们从Page1.xaml导航到Page2.xaml。当您调用NavigationService.Navigate方法时,导航周期开始

  • 第一次第1页的事件导航
  • 然后第2页构造函数激发
  • 然后,OnNavigatedFromPage1的事件在其事件参数中引用创建的页面激发(e.Content具有创建的Page2实例)
  • 最后on导航到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中,我们只需调用
    导航(“/Page2.xaml”,myComplexObject)
    。在您的Page2.xaml.cs中,我们将覆盖OnParameterReceived方法

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

    而且,在PhoneApplicationBasePage

    中稍加调整也可以处理墓碑问题,我希望我能回复上面vjsrinath的回复;这是最好的方法。非常感谢

    这可能是我见过的最接近iOS模型工作原理的东西,从第一页开始,您称之为performsgue(=NavigateTo)。然后您会得到一个名为prepareforsgue的回调,它允许您在目标页面中设置变量,设置委托(通常为self),诸如此类

    对于复杂的对象传递,它可以轻松地传递URL中的参数

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

    在调用类中:

    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”等回调,因此保存处理可以在调用类中完成,而不是在呈现的视图中完成,这对于代码整洁来说是非常糟糕的。e、 g

    page.OnSaveButtonPressed = this.SaveButtonPressedHandler; // Pass object to save as parameter
    
    是不是你不想做序列化,但不介意推卸责任?如果是这样的话,我听说
    IsolatedStorage
    已经得到了改进-可以吗