如何拦截Xamarin表单中单击的导航栏返回按钮?
我有一个xamarin表单页面,用户可以在其中更新表单中的一些数据。我需要截获点击的导航栏后退按钮,以警告用户某些数据尚未保存。如何操作 我可以使用如何拦截Xamarin表单中单击的导航栏返回按钮?,xamarin,xamarin.forms,xamarin.android,xamarin-studio,Xamarin,Xamarin.forms,Xamarin.android,Xamarin Studio,我有一个xamarin表单页面,用户可以在其中更新表单中的一些数据。我需要截获点击的导航栏后退按钮,以警告用户某些数据尚未保存。如何操作 我可以使用Android.MainActivity.OnBackPressed()截获Android中单击的硬件栏后退按钮,但该事件仅在单击硬件栏后退按钮时引发,而不是在单击导航栏后退按钮时引发 我还试图覆盖Xamarin.Forms.NavigationPageOnBackButtonPressed(),但它不起作用。为什么? 有人已经解决了这个问题吗 我还
Android.MainActivity.OnBackPressed()
截获Android中单击的硬件栏后退按钮,但该事件仅在单击硬件栏后退按钮时引发,而不是在单击导航栏后退按钮时引发
我还试图覆盖Xamarin.Forms.NavigationPageOnBackButtonPressed()
,但它不起作用。为什么?
有人已经解决了这个问题吗
我还尝试重写OnDisappear()
,有两个问题:
那么,是否有可能截获导航栏上的后退按钮按下?这本来就是一项困难的任务,我绕过它的唯一方法是完全删除后退按钮,然后从“保存”按钮处理后退导航 我对Xamarin.Forms论坛进行了简短搜索,并提出以下建议:
public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)
{
return false;
}
该帖子的链接如下:
在Xamarin.Forms中,该类有一个方法可供您在所有平台上使用,正如@JordanMazurke也提到的,因为后退按钮的事件当前无法处理(Android的物理后退按钮除外),它是:
NavigationPage.ShowHasBackButton(此,false)
模式
而不是页面
ActionbarItem
,从中可以处理事件
我个人就此事与Xamarin的iOS团队进行了交谈,他们基本上告诉我,对于导航栏中按下的BackButtonPressed
,我们不应该期望得到处理事件的支持。原因是,在iOS上,用户在按下Back
时收到消息是一种不好的做法 我能够显示一个确认对话框,该对话框可以通过覆盖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];
正如前面所说的,您不能跨平台执行此操作。但是,您可以通过本机方式处理它,可以说不需要太多的努力:
本文介绍了iOS和Android。如果你有一个UWP项目,你必须为它敲打你自己的解决方案
编辑:
这是UWP解决方案!事实证明,这非常简单–只有一个后退按钮,并且表单支持它,因此您只需覆盖ContentPage的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);
}
}
我发现最好的方法是添加我自己的NavigationRenderer来拦截导航方法和一个简单的界面
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomerMobile.Droid.NavigationPageRenderer))]
public class NavigationPageRenderer : Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer
{
public Activity context;
public NavigationPageRenderer(Context context)
: base(context)
{}
protected override Task<bool> OnPushAsync(Page page, bool animated) {...}
protected override Task<bool> OnPopToRootAsync(Page page, bool animated){...}
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
// if the page implements my interface then first check the page
//itself is not already handling a redirection ( Handling Navigation)
//if don't then let the handler to check whether to process
// Navitation or not .
if (page is INavigationHandler handler && !handler.HandlingNavigation
&& handler.HandlePopAsync(page, animated))
return Task.FromResult(false);
return base.OnPopViewAsync(page, animated);
}
}
最后,在任何ContentView中,在本例中,当尝试向后导航时,我只是折叠菜单并阻止向后导航
public partial class MenusList : INavigationHandler
{
public bool HandlingNavigation { get; private set; }
public bool HandlePopAsync(Page view, bool animated)
{
HandlingNavigation = true;
try
{
if (Menu.Expanded)
{
Menu.Collapse();
return true;
}
else return false;
}
finally
{
HandlingNavigation = false;
}
}
}
这不会告诉您是否按下了导航后退按钮/图标-仅当按下系统后退按钮时:(这让我很难过。如果有人想在xaml中禁用导航栏的后退按钮,请执行以下操作:不要使用硬编码的数字,我建议使用资源常量。只需将16908332替换为Android.resource.Id.Home即可
public partial class MenusList : INavigationHandler
{
public bool HandlingNavigation { get; private set; }
public bool HandlePopAsync(Page view, bool animated)
{
HandlingNavigation = true;
try
{
if (Menu.Expanded)
{
Menu.Collapse();
return true;
}
else return false;
}
finally
{
HandlingNavigation = false;
}
}
}