2011-01-15 16 views
15

He estado usando Navigate método de la NavigationService 's para navegar a otras páginas en mi WP7 Silverlight aplicación:El paso de un objeto complejo a una página durante la navegación en una aplicación de WP7 Silverlight

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

De Somepage.xaml, que luego recuperar los parámetros de cadena de consulta de la siguiente manera:

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

ahora necesito una manera de pasar un ob complejo se aplica de manera similar. ¿Cómo puedo hacer esto sin tener que serializar el objeto cada vez que necesito pasarlo a una página nueva?

+0

¿Es que _usted_ no quiere hacer la serialización, pero no le importa pasar esa responsabilidad? Si es así, escuché que el 'IsolatedStorage' recibió mejoras, ¿podría ayudar eso? –

+0

Lo realmente importante de entender es, ¿qué debería pasar cuando el usuario presiona el botón Atrás? – AnthonyWJones

Respuesta

14

Este es un problema extremadamente complejo, y no existe una solución simple aquí. No hay una API mágica que funcione para cualquier aplicación que resuelva este problema.

El problema central con el paso de datos de navegación es Tombstoning. La única pieza de datos que se descabeza de forma predeterminada es el URI de navegación. así que si está utilizando un parámetro QueryString, se detectará automáticamente mediante el tombstoning y su código. Sin embargo, cada vez que pases manualmente una instancia de un objeto, tendrás que hacer tombstoning manualmente para esa instancia.

Por lo tanto, si navega a "/CowDetails.xaml?ID=1", su página probablemente tendrá un perfecto tumulto simplemente al seleccionar el parámetro ID Querystring. Sin embargo, si de alguna manera proporciona la página de CowDetails con una "vaca nueva() {ID = 1}", tendrá que asegurarse de hacer un tombstone y zombificar este valor usted mismo.

Además, existe la cuestión del tiempo. Mientras llamas a NavigationService.Navigate, la página que estás navegando tampoco tiene una instancia real todavía. Por lo tanto, aunque esté navegando a FooPage y tenga listo el FooData, no hay forma de conectar FooPage inmediatamente a FooData. Tendrá que esperar hasta que se dispare el evento PhoneApplicationFrame.Navigated para proporcionar FooPage con FooData.

La forma en que normalmente se utiliza este es un problema:

  1. Tener un BasePage con una propiedad Tipo de datos de objetos
  2. tener un NavigationHelper obtener la página URI y Datos: NavigationHelper.Navigate ("foo.xaml ", fooData)
  3. Haga que NavigationHelper se registre en el evento PhoneApplicationFrame.Navigated y, si es" foo.xaml ", establezca BasePage.Data en FooData.
  4. Haga que BasePage use JSON.Net en Tombstone y zombificate BasePage.Data.
  5. En BasePage, tengo un método virtual OnDataSet que se invoca una vez que la propiedad Datos se rellena mediante Zombificación o Navegación. En este método, todo lo que tiene que ver con los datos comerciales ocurre.
+2

¿Un "problema extremadamente complejo"? huh ... –

9

App.xaml.cs -> Clase de aplicación, agregue un campo/propiedad allí. Para acceder a ella, si se trata de un uso estático:

App.MyComplexObject 

O si no es staic

(App.Current as App).MyComplexObject; 
1

Solución discutible, en todo caso, que sea temporal.

Cree esto en el espacio de nombre de su aplicación para la página que sea necesaria.

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; 

Ahora se puede hacer referencia a SomeClassObject, algunalista, somedata en cualquier lugar de la aplicación.

Nota: Al igual que cualquier dato global, esté cansado de los muchos accesos & modificaciones que se pueden hacer a los datos globales. Digo esto, porque una vez tuve un aumento en el tamaño de la lista, pero una de mis páginas en la aplicación dependía del tamaño de la lista para ser de algún valor, y esto causó un error. No lo olvides, los datos son globales.

+0

Esto es exactamente lo que estaba buscando. ¡Gracias! –

5

Hay una solución muy simple para abordar este problema. Consideremos el siguiente ejemplo Una aplicación Windows Phone tiene las siguientes dos páginas, Page1.xaml y Page2.xaml permite decir desde Page1.xaml estamos navegando a Page2.xaml. El ciclo se inicia la navegación, cuando se llama NavigationService.Navigate método

  1. Primera OnNavigatingFrom caso de Página1 incendios
  2. Entonces Constructor de Página2 incendios
  3. Entonces OnNavigatedFrom evento de Página1 incendios con la referencia de la creación Página D en sus EventArgs (e.Content tiene la instancia creada de Página2)
  4. Finalmente OnNavigatedTo caso de Página2 incendios

Así que estamos obteniendo de referencia de la página de la página donde comienza la navegación

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 
} 
} 

Así que en nuestro Page1.xaml.cs simplemente llamamos Navigate("/Page2.xaml",myComplexObject). Y en su Page2.xaml.cs que anulará OnParameterReceived método

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

y también es posible manejar los problemas de lápidas con pequeños retoques más en PhoneApplicationBasePage

+0

Hola, soy nuevo en el desarrollo de teléfonos con Windows. Entendí su solución y me gustó. Pero cuando extiendo el Page.xaml.cs con mi BaseClass, me está dando la excepción de tiempo de ejecución de que las clases parciales deben extender la misma clase base. ¿Puede sugerir? ¿Cómo creo BaseClass que extiende la clase PhoneApplicationPage y luego Page1.xaml.cs extenderá la BaseClass? –

+0

Agregue la referencia del espacio de nombres de ** 'PhoneApplicationBasePage' ** a xaml. Para un ejemplo si su clase está bajo el espacio de nombres ** "Ejemplo" **, entonces se puede agregar una referencia a xaml como este ** 'xmlns: sample = "clr-namespace: Sample' **. En caso de que haya creado esto clase en un ensamblado separado "SampleAssembly", su referencia en xaml debe ser ** 'xmlns: sample = "clr-namespace: Sample; assembly: SampleAssembly' ** Luego reemplace ** 'phone: PhoneApplicationPage' ** tag with ** 'sample: PhoneApplicationBasePage' **. La clase base de tu código detrás y lo que se define en xaml debe ser el mismo. – vjsrinath

1

Me gustaría poder responder a la respuesta de vjsrinath arriba; es IMO la mejor manera de hacer esto. ¡¡Muchas gracias!!

Probablemente es lo más parecido que he visto a la forma en que funciona el modelo de iOS, donde desde la primera página llamas a performSegue (== NavigateTo).A continuación, obtiene una devolución de llamada llamada prepareForSegue, que le permite configurar variables en la página de destino, establecer el delegado (generalmente en sí mismo), ese tipo de cosas.

Para pasar objetos complejos, supera a los pantalones que pasan los parámetros en la URL.

Como un ejemplo explícito, digo que quiero pasar a la cadena de versión de mi aplicación en un cuadro Acerca de que está en un proyecto separado:

En la clase de llamada:

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); 
    } 

En el Sobre clase:

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; 
    } 
} 

este es un ejemplo muy simple, por supuesto, pero la propiedad que está pasando a través podría ser cualquier objeto, por lo que esta muy potente. Por supuesto, puede incluir devoluciones de llamadas como "saveButtonPressed", etc. por lo que el manejo de guardado se puede realizar en la clase de llamada, no en la vista presentada, que es bastante mala para el orden del código. por ejemplo,

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