Xamarin Forms - Найти текущую страницу приложения из класса, не являющегося частью ContentPage

2

Мой вопрос не так прост, как говорит название. Я знаю, что я могу использовать стек навигации, чтобы узнать самую верхнюю страницу и вызвать событие навигации на этой странице.

Это то, что я планировал делать.

        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) может быть передан строкой для имени страницы, и этот вспомогательный класс может разрешить это имя и перейти на страницу, если это существует. К вспомогательному классу обращаются через специфические для платформы реализации после события на телефоне (нажатие на уведомление)

Теги:
modal-dialog
xamarin.forms
navigation
static

2 ответа

3
Лучший ответ

(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;
} 
  • 0
    Это очень близко к тому, что я в итоге реализовал - спасибо, что нашли время ответить!
  • 0
    В начале этого ответа я добавил новое Решение № 2, которое, как мне кажется, является лучшим способом решения проблем, чем использование метода OnAppearing (). Проблема, которую я обнаружил с OnAppearing, заключается в том, что в UWP он вел себя не так, как в iOS / Droid.
0

Вместо того, чтобы напрямую нажать PushModalSync, почему бы не создать его сначала и сохранить в статической переменной в приложении. Таким образом, вы всегда можете ссылаться на него, когда захотите. Оттуда вы можете определить, какая страница является текущей страницей, или сделать любой навигационный обход, который вам нужно сделать.

Application.MyStaticVariable = new NavigationPage(new MainMenu());
await Navigation.PushModalAsync(Application.MyStaticVariable);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню