Передача сложного объекта на страницу при навигации в приложении WP7 Silverlight - PullRequest
15 голосов
/ 15 января 2011

Я использовал NavigationService метод Navigate для перехода на другие страницы в моем приложении WP7 Silverlight:

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

Из Somepage.xaml я затем получаю параметры строки запроса следующим образом:

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

Теперь мне нужен способ передать сложный объект аналогичным образом . Как я могу сделать это без необходимости сериализации объекта каждый раз, когда мне нужно передать его на новую страницу?

Ответы [ 5 ]

14 голосов
/ 18 января 2011

Это чрезвычайно сложная проблема, и здесь нет простого решения.Не существует волшебного API, который бы работал для любого приложения для решения этой проблемы.

Основная проблема при передаче навигационных данных - Tombstoning .Единственный фрагмент данных, который захоронен по умолчанию, - это URI навигации.так что, если вы используете параметр QueryString, он будет автоматически обнаружен захоронением и вашим кодом.В любой момент, когда вы вручную передадите экземпляр объекта, вам придется вручную сделать надгробие для этого экземпляра.

Итак, если вы перейдете к "/CowDetails.xaml?ID=1", то вашстраница, вероятно, будет иметь идеальное надгробие, просто взяв параметр ID Querystring.Тем не менее, если вы каким-либо образом предоставите странице CowDetails "new Cow () {ID = 1}", вам нужно будет убедиться в том, что она захоронит и зомбифицирует это значение самостоятельно.

Также существует проблема синхронизации .При вызове 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 для захоронения и зомбирования BasePage.Data.
  5. На BasePage у меня есть виртуальный метод OnDataSet, который вызывается, когда свойство Data заполняется с помощью Zombification или Navigation.В этом методе происходит все, что связано с бизнес-данными.
9 голосов
/ 15 января 2011

App.xaml.cs -> Класс приложения, добавьте туда поле / свойство. Чтобы получить к нему доступ, если он статический, используйте:

App.MyComplexObject

Или, если не в порядке

(App.Current as App).MyComplexObject;
5 голосов
/ 31 октября 2012

Существует очень простое решение для решения этой проблемы. Рассмотрим следующий пример Приложение для Windows Phone имеет следующие две страницы: Page1.xaml и Page2.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

1 голос
/ 21 марта 2013

Хотел бы я ответить на ответ vjsrinath выше;это IMO лучший способ сделать это.Большое спасибо !!

Это, наверное, самая близкая вещь, которую я видел, к тому, как работает модель iOS, где с первой страницы вы назвали executeSegue (== NavigateTo).Затем вы получаете обратный вызов с именем prepareForSegue, который позволяет вам устанавливать переменные на целевой странице, устанавливать делегата (обычно на себя), что-то в этом роде.

Для прохождения сложных объектов он отбивает штаныпередача параметров в URL.

В качестве явного примера, скажем, я хочу передать строку версии моего приложения в поле 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
1 голос
/ 11 сентября 2012

Дискуссионное решение, во всяком случае, сделать его временным.

Создайте это в пространстве имен вашего приложения для любой необходимой страницы.

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 в любом месте приложения.

Примечание: Как и любые глобальные данные, будьте осторожны со многими доступами и изменениями, которые могут быть выполнены с глобальными данными. Я говорю это, потому что у меня когда-то увеличился размер списка, но одна из моих страниц в приложении полагается, что размер списка имеет какое-то значение, и это вызвало ошибку. Не забывайте, данные являются глобальными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...