Как перехватить кнопку навигации на панели навигации, нажатой в Xamarin Forms?
У меня есть страница формы xamarin, где пользователь может обновлять некоторые данные в форме. Мне нужно перехватить кнопку "Навигационная панель". Нажмите "Отправить", чтобы предупредить пользователя, если некоторые данные не были сохранены. Как это сделать?
Я могу перехватить аппаратную панель Bar Back Button, нажав на Android, используя Android.MainActivity.OnBackPressed()
, но это событие поднимается только на аппаратной панели Back Button Clicked, а не на панели навигации Back Button Clicked.
Я также попытался переопределить Xamarin.Forms.NavigationPageOnBackButtonPressed()
, но он не работает. Зачем?
Кто-то уже решил эту проблему?
Я также попытался переопределить OnDisappear()
, есть две проблемы:
- Страница уже визуально исчезла, так что "Вы уверены?" на предыдущей странице появится диалоговое окно.
- Невозможно отменить действие назад.
Итак, можно ли перехватить кнопку назад на панели навигации?
Ответы
Ответ 1
Мне удалось показать диалог подтверждения, который может отменить навигацию, переопределив следующие методы в FormsApplicationActivity.
// navigation back button
public override bool OnOptionsItemSelected(IMenuItem item)
{
if (item.ItemId == 16908332)
{
var currentViewModel = (IViewModel)navigator.CurrentPage.BindingContext;
currentViewModel.CanNavigateFromAsync().ContinueWith(t =>
{
if (t.Result)
{
navigator.PopAsync();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
return false;
}
else
{
return base.OnOptionsItemSelected(item);
}
}
// hardware back button
public async override void OnBackPressed()
{
var currentViewModel = (IViewModel)navigator.CurrentPage.BindingContext;
// could display a confirmation dialog (ex: "Cancel changes?")
var canNavigate = await currentViewModel.CanNavigateFromAsync();
if (canNavigate)
{
base.OnBackPressed();
}
}
Navigator.CurrentPage - обертка вокруг службы INAVIGATION. Мне не нужно отменять навигацию с модальных страниц, поэтому я обрабатываю только NavigationStack.
this.navigation.NavigationStack[this.navigation.NavigationStack.Count - 1];
Ответ 2
Самый простой, поскольку @JordanMazurke также несколько упоминает, поскольку событие для кнопки "Назад" не может быть обработано в настоящее время (кроме физической кнопки "Назад" для Android), либо:
-
NavigationPage.ShowHasBackButton(this, false)
- Нажатие
Modal
вместо Page
Затем после этого вы можете добавить ActionbarItem
, где вы можете обрабатывать Event
.
Я лично говорил с командой iOS от Xamarin по этому вопросу, и они в основном сказали мне, что мы не должны ожидать поддержки обработки Event
для BackButtonPressed
в NavigationBar
. Причина в том, что на iOS плохой практикой для пользователей получать сообщение при нажатии Back
.
Ответ 3
Это неотъемлемо трудная задача, и единственный способ, которым я обходился, состоял в том, чтобы полностью удалить кнопку "Назад", а затем обработать обратную навигацию с помощью кнопки "Сохранить".
Я провел краткий поиск форума Xamarin.Forms, и было предложено следующее:
public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)
{
return false;
}
Ссылка на сообщение следующая:
https://forums.xamarin.com/discussion/21631/is-there-nay-way-of-cancelling-the-back-button-event-from-the-navigationpage
Ответ 4
Как уже было сказано, вы не можете сделать эту кросс-платформу. Однако вы можете справиться с этим, возможно, не так много усилий: https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/
В этой статье рассматриваются iOS и Android. Если у вас есть проект UWP, вам придется забить свое собственное решение.
Изменить:
Вот решение UWP! На самом деле это оказалось довольно просто - есть только одна кнопка назад и ее поддержка форм, поэтому вам просто нужно переопределить ContentPages OnBackButtonPressed:
protected override bool OnBackButtonPressed()
{
if (Device.RuntimePlatform.Equals(Device.UWP))
{
OnClosePageRequested();
return true;
}
else
{
base.OnBackButtonPressed();
return false;
}
}
async void OnClosePageRequested()
{
var tdvm = (TaskDetailsViewModel)BindingContext;
if (tdvm.CanSaveTask())
{
var result = await DisplayAlert("Wait", "You have unsaved changes! Are you sure you want to go back?", "Discard changes", "Cancel");
if (result)
{
tdvm.DiscardChanges();
await Navigation.PopAsync(true);
}
}
else
{
await Navigation.PopAsync(true);
}
}
Ответ 5
В Xamarin.Forms класс Page имеет OnBackButtonPressed()
, который вы можете использовать для всех платформ.