Мой вопрос не так прост, как говорит название. Я знаю, что я могу использовать стек навигации, чтобы узнать самую верхнюю страницу и вызвать событие навигации на этой странице.
Это то, что я планировал делать.
Page currentPage;
int index = Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
currentPage = Application.Current.MainPage.Navigation.NavigationStack[index];
//after getting the correct page..
//await currentPage.Navigation.PushAsync(new SomePage());
Моя проблема в том, что индекс возвращается как -1
. Я полагаю, что есть еще одна сложность из-за моей иерархии/структуры страницы.
Главная страница моих приложений - это LoginPage
- и как только пользователь успешно LoginPage
вход в систему, они LoginPage
на страницу Modal, после чего остальная часть навигации будет проходить оттуда.
await Navigation.PushModalAsync(new NavigationPage(new MainMenu()));
Как я могу найти текущую активную страницу (которую пользователь просматривает) - из класса, который не наследуется от ContentPage, когда NavigationStack включает в себя модальную страницу?
Мне нужно сделать это так, чтобы мой статический класс "помощник" (к которому обращается доступ к платформе для iOS/Android) может быть передан строкой для имени страницы, и этот вспомогательный класс может разрешить это имя и перейти на страницу, если это существует. К вспомогательному классу обращаются через специфические для платформы реализации после события на телефоне (нажатие на уведомление)
(NEW) РЕШЕНИЕ №2
Другой способ сделать это - подклассифицировать классы NavigationPage, TabbedPage, а затем использовать события навигации, которые Xamarin дает нам для отслеживания текущей страницы. Эти события: ModalPushed, ModalPopped, Pushed, Popped, CurrentPageChanged и т.д.
Это немного больше кода, но это более предсказуемое поведение на всех платформах, и вам не нужно сохранять какое-либо дополнительное состояние, если приложение помещается в фоновый режим.
1) App.xaml.cs
public App()
{
...
this.ModalPushed += OnModalPushed;
this.ModalPopped += OnModalPopped;
}
//keep track of any modals presented
private readonly Stack<Page> ModalPages = new Stack<Page>();
void OnModalPushed(object sender, ModalPushedEventArgs e)
{
ModalPages.Push(e.Modal);
PageService.CurrentPage = FindCurrentPage();
}
void OnModalPopped(object sender, ModalPoppedEventArgs e)
{
ModalPages.Pop();
PageService.CurrentPage = FindCurrentPage();
}
public Page FindCurrentPage()
{
//If there is a Modal present, start there, or else start in the MainPage
Page root = ModalPages.Count > 0 ? ModalPages.Peek() : this.MainPage;
var tabbedPage = root as TabbedPage;
if (tabbedPage != null)
{
var currentTab = tabbedPage.CurrentPage;
var navPage = currentTab as NavigationPage;
if (navPage != null)
{
return navPage.CurrentPage;
}
else
{
return currentTab;
}
}
else
{
var navPage = root as NavigationPage;
if (navPage != null)
{
return navPage.CurrentPage;
}
return root;
}
}
2) CustomNavigationPage.cs
//All NavigationPage in your app should use this class!
public class CustomNavigationPage : NavigationPage
{
public BaseNavigationPage(Page page) : base(page)
{
this.Pushed += OnPushed;
this.Popped += OnPopped;
}
void OnPushed(object sender, NavigationEventArgs e)
{
PageService.CurrentPage = e.Page;
}
void OnPopped(object sender, NavigationEventArgs e)
{
PageService.CurrentPage = ((App)App.Current).FindCurrentPage();
}
}
3) CustomTabbedPage.cs --- только если ваше приложение использует вкладки
public class CustomTabbedPage : TabbedPage
{
public CustomTabbedPage()
{
this.CurrentPageChanged += OnTabbedPageTabChanged;
}
void OnTabbedPageTabChanged(object sender, EventArgs e)
{
PageService.CurrentPage = ((App)App.Current).FindCurrentPage();
}
}
4) PageService.cs
public static class PageService
{
public Page CurrentPage
{
get;
set;
}
}
(ОРИГИНАЛ) РЕШЕНИЕ № 1
Что для меня работало, было использование статического класса для отслеживания страницы, на которой в данный момент находится пользователь. У меня есть все мои ContentPages, наследующие BasePage, который устанавливает текущую страницу в OnAppearing(). В Android вам также придется обрабатывать особую ситуацию, когда приложение приостанавливает/возобновляет работу, потому что Xamarin будет вызывать OnAppearing на корневой странице приложения (не обязательно на странице).
Этот метод позволяет мне делать такие действия, как Push/Pop-страницы, из любого места на моем уровне viewmodel, не связывая ViewModel напрямую с представлением.
PageService.cs:
public static class PageService
{
public Page CurrentPage
{
get;
set;
}
public Page SavedStatePage
{
get;
set;
}
}
BasePage.cs:
//Have all of your pages inherit this page
public abstract class BasePage : ContentPage
{
public BasePage () : base()
{
}
public override void OnAppearing()
{
protected override void OnAppearing()
{
base.OnAppearing();
//Mainly for Android, restore the current page to the last saved page when the app paused
if( PageService.SavedStatePage != null )
{
PageService.CurrentPage = PageService.SavedStatePage;
PageService.SavedStatePage = null;
}
else
{
//default behavior. Set the current page to the one currently appearing.
PageService.CurrentPage = this;
}
}
}
}
MainActivity.cs (в проекте Droid):
protected override void OnPause()
{
base.OnPause();
//save the current page before app pauses, because Xamarin doesn't always call OnAppearing on the correct page when resume happens
PageService.SavedStatePage = PageService.CurrentPage;
}
Вместо того, чтобы напрямую нажать PushModalSync, почему бы не создать его сначала и сохранить в статической переменной в приложении. Таким образом, вы всегда можете ссылаться на него, когда захотите. Оттуда вы можете определить, какая страница является текущей страницей, или сделать любой навигационный обход, который вам нужно сделать.
Application.MyStaticVariable = new NavigationPage(new MainMenu());
await Navigation.PushModalAsync(Application.MyStaticVariable);