Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何拦截Xamarin表单中单击的导航栏返回按钮?_Xamarin_Xamarin.forms_Xamarin.android_Xamarin Studio - Fatal编程技术网

如何拦截Xamarin表单中单击的导航栏返回按钮?

如何拦截Xamarin表单中单击的导航栏返回按钮?,xamarin,xamarin.forms,xamarin.android,xamarin-studio,Xamarin,Xamarin.forms,Xamarin.android,Xamarin Studio,我有一个xamarin表单页面,用户可以在其中更新表单中的一些数据。我需要截获点击的导航栏后退按钮,以警告用户某些数据尚未保存。如何操作 我可以使用Android.MainActivity.OnBackPressed()截获Android中单击的硬件栏后退按钮,但该事件仅在单击硬件栏后退按钮时引发,而不是在单击导航栏后退按钮时引发 我还试图覆盖Xamarin.Forms.NavigationPageOnBackButtonPressed(),但它不起作用。为什么? 有人已经解决了这个问题吗 我还

我有一个xamarin表单页面,用户可以在其中更新表单中的一些数据。我需要截获点击的导航栏后退按钮,以警告用户某些数据尚未保存。如何操作

我可以使用
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;
            }
        }
    }