Передача сложного объекта на страницу во время навигации в приложении WP7 Silverlight
Я использую метод NavigationService
Navigate
для перехода на другие страницы моего приложения WP7 Silverlight:
NavigationService.Navigate(new Uri("/Somepage.xaml?val=dreas", UriKind.Relative));
Из Somepage.xaml
я затем извлекаю параметры строки запроса следующим образом:
string val;
NavigationContext.QueryString.TryGetValue("val", out val);
Мне теперь нужен способ передать сложный объект с помощью аналогичного метода. Как я могу сделать это без необходимости сериализации объекта каждый раз, когда мне нужно передать его на новую страницу?
Ответы
Ответ 1
Это очень сложная проблема, и здесь нет простого решения. Нет волшебного API, который бы просто работал для любого приложения, чтобы решить эту проблему.
Основная проблема с прохождением навигационных данных - Tombstoning. Единственным фрагментом данных, который по умолчанию является надгробный камень, является URI навигации. поэтому, если вы используете параметр QueryString, он будет автоматически загружаться с помощью гемблинга и вашего кода. Каждый раз, когда вы вручную передаете экземпляр объекта, вам придется вручную выполнить надгробный сбор для этого экземпляра самостоятельно.
Итак, если вы перейдете в "/CowDetails.xaml?ID=1", ваша страница, вероятно, будет иметь идеальное гемблирование, просто набрав параметр ID Querystring. Однако, если вы каким-то образом предоставите страницу CowDetails с "новой Cow() {ID = 1}", вам нужно будет убедиться в том, что захоронение и зомбифицировать это значение самостоятельно.
Кроме того, существует проблема синхронизации. При вызове NavigationService.Navigate страница, которую вы просматриваете, еще не имеет фактического экземпляра. Поэтому, даже если вы переходите к FooPage и имеете FooData, нет никакого способа немедленно подключить FooPage к FooData. Вам придется подождать, пока событие PhoneApplicationFrame.Navigated не будет запущено, чтобы предоставить FooPage с помощью FooData.
Как я обычно справляюсь с этой проблемой:
- У базы BasePage есть свойство Data type Свойство
- Имейте NavigationHelper получить URI страницы и данные: NavigationHelper.Navigate( "foo.xaml", fooData)
- У меня есть NavigationHelper для регистрации на событие PhoneApplicationFrame.Navigated, и если он "foo.xaml", установите BasePage.Data в FooData.
- Если BasePage использует JSON.Net для надгробия и зомбификата BasePage.Data.
- В BasePage у меня есть виртуальный метод OnDataSet, который вызывается, когда свойство Data заполнено либо Zombification, либо Navigation. В этом методе происходит все, что связано с бизнес-данными.
Ответ 2
App.xaml.cs → Класс приложения, добавьте в него поле/свойство. Чтобы получить доступ к нему, если это статическое использование:
App.MyComplexObject
Или, если не является staic
(App.Current as App).MyComplexObject;
Ответ 3
Там очень простое решение для решения этой проблемы. Рассмотрим следующий пример
Приложение Windows Phone имеет следующие две страницы: Page1.xaml и Page2.xaml
Скажем, из Page1.xaml мы переходим к Page2.xaml. Навигационный цикл начинается, когда вы вызываете метод NavigationService.Navigate
- Первый OnNavigatingFrom Событие Page1 срабатывает
- Затем Конструктор из Page2 срабатывает
- Затем OnNavigatedFrom событие Page1 запускается со ссылкой на созданную страницу в EventArgs (e.Content имеет созданный экземпляр Page2)
- Наконец 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
Ответ 4
Дискуссионное решение, во всяком случае, делает его временным.
Создайте это под пространством имен вашего приложения для любой необходимой страницы.
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 в любом месте приложения.
Примечание. Как и любые глобальные данные, утомляйтесь многочисленными обращениями и изменениями, которые могут быть сделаны для глобальных данных. Я говорю это, потому что у меня когда-то было увеличение списка по размеру, но одна из моих страниц в приложении полагалась на размер списка, чтобы иметь какое-то значение, и это вызвало ошибку. Не забывайте, что данные глобальны.
Ответ 5
Хотелось бы, чтобы я ответил на ответ vjsrinath выше; это ИМО лучший способ сделать это. Большое спасибо!
Скорее всего, это самая близкая вещь, которую я видел, как работает модель iOS, где с первой страницы вы назвали performSegue (== NavigateTo). Затем вы получаете обратный вызов под названием prepareForSegue, который позволяет вам устанавливать переменные на целевой странице, устанавливать делегат (обычно для себя), что-то вроде этого.
Для передачи сложного объекта он удаляет пропущенные параметры переноса в 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" и т.д., Поэтому обработка сохранения может быть выполнена в вызывающем классе, а не в представленном представлении, что довольно красно для удобства кода. например.
page.OnSaveButtonPressed = this.SaveButtonPressedHandler; // Pass object to save as parameter