Оболочка Xamarin Forms — переход к старому стеку навигации, а не к всплывающей странице

#xamarin #xamarin.forms

#xamarin #xamarin.forms

Вопрос:

У меня возникли проблемы с моим приложением оболочки Xamarin Forms. Я не уверен, является ли это ошибкой или ожидаемым поведением, может кто-нибудь указать мне правильное направление.

У меня есть приложение с 2 страницами в иерархии визуальной оболочки:

Поиск и история

 <FlyoutItem Title="Search" Icon="search.png">
    <Tab Title="Search">
        <ShellContent Route="searchpage">
            <views:SearchPage />
        </ShellContent>
    </Tab>
</FlyoutItem>
<FlyoutItem Title="History" Icon="history.png">
    <Tab Title="History">
        <ShellContent>
            <views:HistoryPage />
        </ShellContent>
    </Tab>
</FlyoutItem>
  

И несколько страниц (назовем их PageA, PageB и PageC) зарегистрированы следующим образом:

 Routing.RegisterRoute("PageA", typeof(PageA));    
Routing.RegisterRoute("PageB", typeof(PageB));    
Routing.RegisterRoute("PageC", typeof(PageC)); (Oops, I should probably use nameof here)
  

В любом случае, я начинаю со страницы поиска и перехожу на страницу следующим образом:

 Shell.Current.GoToAsync("PageA");
  

Поскольку PageA отсутствует в визуальной иерархии, это дает мне стек навигации следующим образом:

 "//searchpage/PageA"
  

Используя тот же относительный подход к навигации, я перехожу к PageB, а затем к PageC, поэтому мой стек навигации выглядит так:

 "//searchpage/PageA/PageB/PageC"
  

Из PageC я использую всплывающее меню для перехода к истории, страница истории открывается нормально.

Теперь на странице истории я снова использую всплывающее меню и нажимаю вкладку Поиска

Но я не попадаю на страницу поиска, как ожидалось, я возвращаюсь к PageC (возвращаюсь к моему предыдущему стеку навигации).

С этой страницы (PageC), если я снова использую всплывающее меню и нажимаю вкладку Поиска, он правильно переходит на страницу поиска.

Как это должно работать и как я могу остановить переход к PageC при выборе вкладки поиска во всплывающем окне?

Спасибо

(ps — в настоящее время я использую Xamarin Forms 4.7)

Комментарии:

1. То же самое поведение с официальным образцом проекта

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

3. Кроме того, при использовании Shell.Current.GoToAsync на следующей странице меню отображаться не FlyoutIcon будет. Поэтому из PageC вы можете поделиться кодом того, как использовать всплывающее меню для перехода к истории.

4. @Craig Однако я не смог найти способ переопределить событие щелчка элемента flayout. Возможно, вы могли бы отправить запрос функции в Github здесь . Тогда будут инженеры из Microsoft, чтобы знать потребности. Если они примут этот запрос функции, они обновят его в следующей версии xamrin forms. Если вы отправили его, не забудьте поделиться ссылкой здесь. Я также буду следить за этим там.

5. @JuniorJiang-MSFT Да, конечно, я отправлю запрос на эту функцию и поделюсь ссылкой, когда это будет сделано. Спасибо за вашу помощь.

Ответ №1:

Для тех, кто все еще ищет ответы, ответ от Damir’s Corner

 await Shell.Current.GoToAsync($"///{tag}", false); //Checks the Navigation Stack Downward
  

Приведенный выше код проверяет текущий стек навигации и выполняет поиск тега маршрута вниз (или внутри стека навигации), а затем заменяет весь стек найденным маршрутом.

Надеюсь, это поможет тем, кто ищет ответы.

Ответ №2:

При переходе между разными вкладками (и, таким образом, разными стеками навигации) решение Williams (угол Дамира) сработало для меня.

Мой сценарий:

  • Tab1 -> Страница списка -> Страница сведений
  • Tab2 -> CreateStep1Page -> CreateStep2Page

После сохранения записи в CreateSpecificPage я перемещаюсь два раза:

 await Shell.Current.GoToAsync($"///{nameof(CreateStep1Page)}", false);
await Shell.Current.GoToAsync($"///{nameof(ListPage)}/{nameof(DetailsPage)}", true);
  

Ответ №3:

Я буду поднимать это как запрос функции, когда у меня будет 5 минут, но я нашел решение этой проблемы.

  1. Я сделал последнюю страницу (PageC) корневой страницей и удалил ее из своего скрипта маршрутов. Я сделал это, добавив следующее в оболочку приложения.Xaml вот так:

     <ShellItem Route="PageC">
        <ShellContent ContentTemplate="{DataTemplate views:PageC}" />
    </ShellItem>
    
    and removing this code:
    Routing.RegisterRoute("PageC", typeof(PageC));
      
  2. Теперь при переходе к PageC я больше не нажимаю на стек с относительной навигацией, теперь я перехожу на корневую страницу следующим образом:

      await Shell.Current.GoToAsync("//PageC");
      
  3. Прежде чем перейти к PageC, нам нужно очистить текущий стек навигации. Я попробовал PopToRootAsync, но это показало страницу поиска перед переходом к странице. Я обнаружил, что работает следующий код:

          // FYI - Navigation Stack: //SearchPage/PageA/PageB
    
         var pageB = Shell.Current.Navigation.NavigationStack[2];
         var pageA = Shell.Current.Navigation.NavigationStack[1];
    
         Shell.Current.Navigation.RemovePage(pageB);
         Shell.Current.Navigation.RemovePage(pageA);
    
         // Now navigate to our route page, PageC.
         await Shell.Current.GoToAsync("//PageC");
      

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

В следующий раз, когда я перейду на страницу поиска, я получу страницу поиска

Комментарии:

1. Рад, что нашел решение! Не забудьте отметить это как ответ, когда у вас будет время. Тогда другие, у которых такие же потребности, будут знать это.

2. @Craig Правильно ли это, если для очистки стека нужно добавить страницу в визуальную иерархию оболочки?

3. @ThamaraiT Нет, чтобы очистить стек, вам нужно перейти к корню. Добавление страницы в визуальную иерархию просто позволяет этой странице быть корневой страницей.

4. Необходимо отправить запрос функции, поскольку в официальном документе говорится, что страница всегда находится в корневом каталоге, когда страница определена в визуальной иерархии оболочки. learn.microsoft.com/en-us/xamarin/xamarin-forms /…

5. @ThamaraiT Это уже так. Только когда вы добавляете страницу (страница 2 на страницу 1 … добавление страницы, которой нет в визуальной иерархии) … страница 2 остается на месте, когда вы переходите и возвращаетесь к странице 1 при использовании меню.

Ответ №4:

Я думаю, что эта функция является преднамеренной. Следует понимать, что, как указано в документах, каждая вкладка содержит отдельный стек навигации, оболочку.Current.Navigation указывает на текущий активный / видимый стек навигации по вкладкам. Итак, то, что вы можете сделать, на самом деле довольно просто.

Вы просто переопределяете Shell.Событие OnNavigating и из удалите все страницы, кроме корневой, из текущего стека навигации, только если вы перемещаетесь между разными деревьями маршрутов.

Например, из //route1/page1 в //route2/page2 .

Вы можете адаптировать следующий код для вашего варианта использования.

 public partial class AppShell : Xamarin.Forms.Shell
{
    public AppShell()
    {
        InitializeComponent();

        Setup.RegisterRoutes(this);
    }

    protected override void OnNavigating(ShellNavigatingEventArgs args)
    {
        base.OnNavigating(args);

        if (args.Current != null amp;amp; args.Target != null amp;amp; args.Current.Location.OriginalString.StartsWith("//") amp;amp; args.Target.Location.OriginalString.StartsWith("//")) {
            var currentRoot = args.Current.Location.OriginalString.TrimStart('/').Split('/').First();
            var targetRoot = args.Target.Location.OriginalString.TrimStart('/').Split('/').First();
            
            // we are navigating between tabs
            if (!string.Equals(currentRoot, targetRoot, StringComparison.OrdinalIgnoreCase) amp;amp; Navigation.NavigationStack.Count > 1) {
                for (var i = Navigation.NavigationStack.Count - 1; i > 0; i--) {
                    Navigation.RemovePage(Navigation.NavigationStack[i]);
                }
            }
        }
    }
}