0
votes

I'm trying to pop the current view page off of the navigation stack in a Xamarin Forms app in the App.OnSleep method. This method fires when the app is "suspending". (Suspending seems to map to 1 or more events in different platforms.)

The following works beautifully in my UWP app (I'm only popping if it's a particular page):

var currentPage = this.MainPage as NavigationPage; // MainPage = new NavigationPage(new MainPage())
if (currentPage != null && currentPage.CurrentPage is FooPage)
{
    // FooPage was shown from MainPage with Navigation.PushAsync(new FooPage())
    var fooPage = currentPage.CurrentPage as FooPage;
    currentPage.PopAsync().Wait();
}

When I suspend and resume the UWP app the previous navigation page is visible. In the iOS (11.2) app, the FooPage is still visible but the controls on it don't respond.

I've tried using NavigationProxy.PopAsync.Wait() but I get an exception in iOS.

Is this just a case of Xamarin Forms's OnSleep not offing enough support on iOS? Or is OnSleep firing in an event on iOS where I can't do this? Or am I missing something basic because I'm new to Xamarin?

Update:

Stacktrace from NavigationProxy.PopAsync:

System.InvalidOperationException: PopAsync is not supported globally on iOS, please use a NavigationPage.
  at Xamarin.Forms.Platform.iOS.Platform.Xamarin.Forms.INavigation.PopAsync (System.Boolean animated) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\Platform.cs:113 
  at Xamarin.Forms.Internals.NavigationProxy.OnPopAsync (System.Boolean animated) [0x00007] in D:\agent\_work\1\s\Xamarin.Forms.Core\NavigationProxy.cs:162 
  at Xamarin.Forms.Internals.NavigationProxy.PopAsync () [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\NavigationProxy.cs:74 
  at InstMobile.App.ClearView () [0x00057] in C:\Users\jmclachlan\Source\Repos\InstG\Inst\InstMobile\App.xaml.cs:66 
  at InstMobile.App.OnSleep () [0x0000c] in C:\Users\jmclachlan\Source\Repos\InstG\Inst\InstMobile\App.xaml.cs:39 
  at Xamarin.Forms.Application.SendSleepAsync () [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\Application.cs:247 
  at Xamarin.Forms.Platform.iOS.FormsApplicationDelegate+OnResignActivation>d__8.MoveNext () [0x00023] in D:\agent\_work\1\s\Xamarin.Forms.Platform.iOS\FormsApplicationDelegate.cs:71 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.4/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:152 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.4/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018 
  at UIKit.UIKitSynchronizationContext+<Post>c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/5665/db807ec9/source/xamarin-macios/src/UIKit/UIKitSynchronizationContext.cs:24 
  at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Use
rs/builder/data/lanes/5665/db807ec9/source/xamarin-macios/src/Foundation/NSAction.cs:163 
  at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/5665/db807ec9/source/xamarin-macios/src/UIKit/UIApplication.cs:79 
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/5665/db807ec9/source/xamarin-macios/src/UIKit/UIApplication.cs:63 
  at InstMobile.iOS.Application.Main (System.String[] args) [0x00001] in C:\Users\jmclachlan\Source\Repos\InstG\Inst\InstMobile.iOS\Main.cs:17 

So it's firing in OnResignActivation. Is this too late for certain UI changes?

1
OnSleep is firing from UIApplicationDelegate's applicationWillResignActive and while I have "cleaned" up the UI in Xamarin.iOS (and ObjC/Swift) native within this message, I have not done it in Forms. There are a few rdars about performing UIKit work in this method, being most are solved by resigning the first responder (which Xamarin.Forms does not do). So what actually is the Exception (and StackTrace) that you are getting? And is the keyboard showing or not?SushiHangover
Added the stack trace for NavigationProxy.PopAsync. No, the keyboard isn't showing in the UI when I call either PopAsync method. What's an rdar?James McLachlan
Your error has nothing to do with it begin used within OnSleep, PopAsync/PushAsync/PopToRootAsync, as the error states, is not supported globally on iOS. You need to wrap your context page in a NavigationPage, i.e. stackoverflow.com/a/45120136/4984832 (and a radr is an Apple bug report)SushiHangover

1 Answers

0
votes

I made 2 changes that seem to have made this work. I don't know which, but that's ok. I used the page's Navigation property and removed the Wait() call on PopAsync(). Could this cause timing issues where the pop doesn't complete before the app goes to sleep? Maybe that's a question for another day.

var currentPage = this.MainPage as NavigationPage; // MainPage = new NavigationPage(new MainPage())
if (currentPage != null && currentPage.CurrentPage is FooPage)
{
    // FooPage was shown from MainPage with Navigation.PushAsync(new FooPage())
    currentPage.Navigation.PopAsync();
}