Thursday, August 17, 2017

Popped Pages in Xamarin Forms

This post is long overdue. About a year ago (July 2016) I managed to get some code into Xamarin Forms Core. This code change was necessary in order to make TinyPubSub work correctly.


If you call Navigation.PopToRoot() in Xamarin Forms and want to know all the pages being popped you need to cast the NavigationEventArgs to a PoppedToRootEventArgs.

    var page = new NavigationPage();
     page.PoppedToRoot += (object sender, NavigationEventArgs e) => 
         // Typecast the args
         var args = e as PoppedToRootEventArgs;

         // Get the pages
         var poppedPages = args.PoppedPages;

Long story

There was quite a long discussion before I got this change approved by Jason Smith and the Forms team. The most pressing issue was that we could not break the signature of the PoppedToRoot event so we ended up creating a new event args class (called PoppedToRootEventArgs) and simply passed that one in. 

This of course hides the PoppedToRootEventArgs from plain sight so you need to know what you are looking for.

The internal workings of PopToRoot (the important parts) looks like this:

    var args = new NavigationRequestedEventArgs(RootPage, animated);

     EventHandler<NavigationRequestedEventArgs> requestPopToRoot = PopToRootRequested;
     if (requestPopToRoot != null)
         requestPopToRoot(this, args);

         if (args.Task != null)
             await args.Task;

    PoppedToRoot?.Invoke(thisnew PoppedToRootEventArgs(RootPage, childrenToRemove.OfType<Page>().ToList()));

The last line is the event (PoppedToRoot) and as you see we pass in PoppedToRootEventArgs as the args.

The PoppedToRootEventArgs is simply a class inheriting from NavigationEventArgs that adds PoppedPages as a IEnumerable to the class.

    public class PoppedToRootEventArgs : NavigationEventArgs
        public PoppedToRootEventArgs(Page page, IEnumerable<Page> poppedPages) : base(page)
            if (poppedPages == null)
                throw new ArgumentNullException(nameof(poppedPages));

            PoppedPages = poppedPages;

        public IEnumerable<Page> PoppedPages { getprivate set; }

No comments:

Post a Comment