From 3b608a3a5e9b5739014a60995c31dbf610b61de4 Mon Sep 17 00:00:00 2001 From: adrianknight89 Date: Thu, 2 Feb 2017 09:35:23 -0600 Subject: [PATCH] [Core] Added RootPage to NavigationPage (#464) * d * removed whitespace * Using ArgumentNullException * changes --- Xamarin.Forms.Core.UnitTests/NavigationUnitTest.cs | 103 +++++++++++++++++++-- Xamarin.Forms.Core/NavigationPage.cs | 53 +++++++---- .../Xamarin.Forms/NavigationPage.xml | 36 +++++++ 3 files changed, 170 insertions(+), 22 deletions(-) diff --git a/Xamarin.Forms.Core.UnitTests/NavigationUnitTest.cs b/Xamarin.Forms.Core.UnitTests/NavigationUnitTest.cs index d82a97a..fb68d14 100644 --- a/Xamarin.Forms.Core.UnitTests/NavigationUnitTest.cs +++ b/Xamarin.Forms.Core.UnitTests/NavigationUnitTest.cs @@ -14,6 +14,7 @@ namespace Xamarin.Forms.Core.UnitTests { NavigationPage nav = new NavigationPage (); + Assert.IsNull(nav.RootPage); Assert.IsNull (nav.CurrentPage); Label child = new Label {Text = "Label"}; @@ -21,7 +22,9 @@ namespace Xamarin.Forms.Core.UnitTests await nav.Navigation.PushAsync (childRoot); - Assert.AreSame (childRoot, nav.CurrentPage); + Assert.AreSame(childRoot, nav.RootPage); + Assert.AreSame(childRoot, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -40,16 +43,26 @@ namespace Xamarin.Forms.Core.UnitTests bool fired = false; nav.Popped += (sender, e) => fired = true; + + Assert.AreSame(childRoot, nav.RootPage); + Assert.AreNotSame(childRoot2, nav.RootPage); + Assert.AreNotSame(nav.RootPage, nav.CurrentPage); + var popped = await nav.Navigation.PopAsync (); Assert.True (fired); - Assert.AreSame (childRoot, nav.CurrentPage); + Assert.AreSame(childRoot, nav.RootPage); + Assert.AreSame(childRoot, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); Assert.AreEqual (childRoot2, popped); await nav.PopAsync (); var last = await nav.Navigation.PopAsync (); Assert.IsNull (last); + Assert.IsNotNull(nav.RootPage); + Assert.IsNotNull(nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -57,6 +70,7 @@ namespace Xamarin.Forms.Core.UnitTests { NavigationPage nav = new NavigationPage (); + Assert.IsNull(nav.RootPage); Assert.IsNull (nav.CurrentPage); Label child = new Label {Text = "Label"}; @@ -64,7 +78,9 @@ namespace Xamarin.Forms.Core.UnitTests await nav.PushAsync (childRoot); - Assert.AreSame (childRoot, nav.CurrentPage); + Assert.AreSame (childRoot, nav.RootPage); + Assert.AreSame(childRoot, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -96,10 +112,15 @@ namespace Xamarin.Forms.Core.UnitTests bool fired = false; nav.Pushed += (sender, e) => fired = true; + Assert.AreSame(childRoot, nav.RootPage); + Assert.AreSame(childRoot, nav.CurrentPage); + await nav.PushAsync (childRoot); Assert.False (fired); - Assert.AreEqual (childRoot, nav.CurrentPage); + Assert.AreSame(childRoot, nav.RootPage); + Assert.AreSame(childRoot, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -184,7 +205,9 @@ namespace Xamarin.Forms.Core.UnitTests nav.PopToRootAsync (); Assert.True (signaled); - Assert.AreEqual (root, nav.CurrentPage); + Assert.AreSame (root, nav.RootPage); + Assert.AreSame(root, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -209,7 +232,9 @@ namespace Xamarin.Forms.Core.UnitTests Assert.AreEqual (2, poppedChildren.Count); Assert.Contains (child1, poppedChildren); Assert.Contains (child2, poppedChildren); - Assert.AreEqual (root, nav.CurrentPage); + Assert.AreSame(root, nav.RootPage); + Assert.AreSame(root, nav.CurrentPage); + Assert.AreSame(nav.RootPage, nav.CurrentPage); } [Test] @@ -458,6 +483,72 @@ namespace Xamarin.Forms.Core.UnitTests Assert.False (result); } + [Test] + public void TestInsertPage() + { + var root = new ContentPage { Title = "Root" }; + var newPage = new ContentPage(); + var navPage = new NavigationPage(root); + + navPage.Navigation.InsertPageBefore(newPage, navPage.RootPage); + + Assert.AreSame(newPage, navPage.RootPage); + Assert.AreNotSame(newPage, navPage.CurrentPage); + Assert.AreNotSame(navPage.RootPage, navPage.CurrentPage); + Assert.AreSame(root, navPage.CurrentPage); + + Assert.Throws(() => + { + navPage.Navigation.InsertPageBefore(new ContentPage(), new ContentPage()); + }); + + Assert.Throws(() => + { + navPage.Navigation.InsertPageBefore(navPage.RootPage, navPage.CurrentPage); + }); + + Assert.Throws(() => + { + navPage.Navigation.InsertPageBefore(null, navPage.CurrentPage); + }); + + Assert.Throws(() => + { + navPage.Navigation.InsertPageBefore(new ContentPage(), null); + }); + } + + [Test] + public async void TestRemovePage() + { + var root = new ContentPage { Title = "Root" }; + var newPage = new ContentPage(); + var navPage = new NavigationPage(root); + await navPage.PushAsync(newPage); + + navPage.Navigation.RemovePage(root); + + Assert.AreSame(newPage, navPage.RootPage); + Assert.AreSame(newPage, navPage.CurrentPage); + Assert.AreSame(navPage.RootPage, navPage.CurrentPage); + Assert.AreNotSame(root, navPage.CurrentPage); + + Assert.Throws(() => + { + navPage.Navigation.RemovePage(root); + }); + + Assert.Throws(() => + { + navPage.Navigation.RemovePage(newPage); + }); + + Assert.Throws(() => + { + navPage.Navigation.RemovePage(null); + }); + } + [Test (Description = "CurrentPage should not be set to null when you attempt to pop the last page")] [Property ("Bugzilla", 28335)] public async Task CurrentPageNotNullPoppingRoot() diff --git a/Xamarin.Forms.Core/NavigationPage.cs b/Xamarin.Forms.Core/NavigationPage.cs index fdafec0..7663d1b 100644 --- a/Xamarin.Forms.Core/NavigationPage.cs +++ b/Xamarin.Forms.Core/NavigationPage.cs @@ -28,7 +28,10 @@ namespace Xamarin.Forms static readonly BindablePropertyKey CurrentPagePropertyKey = BindableProperty.CreateReadOnly("CurrentPage", typeof(Page), typeof(NavigationPage), null); public static readonly BindableProperty CurrentPageProperty = CurrentPagePropertyKey.BindableProperty; - + + static readonly BindablePropertyKey RootPagePropertyKey = BindableProperty.CreateReadOnly(nameof(RootPage), typeof(Page), typeof(NavigationPage), null); + public static readonly BindableProperty RootPageProperty = RootPagePropertyKey.BindableProperty; + public NavigationPage() { _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); @@ -92,6 +95,12 @@ namespace Xamarin.Forms private set { SetValue(CurrentPagePropertyKey, value); } } + public Page RootPage + { + get { return (Page)GetValue(RootPageProperty); } + private set { SetValue(RootPagePropertyKey, value); } + } + public static string GetBackButtonTitle(BindableObject page) { return (string)page.GetValue(BackButtonTitleProperty); @@ -304,8 +313,14 @@ namespace Xamarin.Forms void InsertPageBefore(Page page, Page before) { + if (page == null) + throw new ArgumentNullException($"{nameof(page)} cannot be null."); + + if (before == null) + throw new ArgumentNullException($"{nameof(before)} cannot be null."); + if (!PageController.InternalChildren.Contains(before)) - throw new ArgumentException("before must be a child of the NavigationPage", "before"); + throw new ArgumentException($"{nameof(before)} must be a child of the NavigationPage", nameof(before)); if (PageController.InternalChildren.Contains(page)) throw new ArgumentException("Cannot insert page which is already in the navigation stack"); @@ -316,6 +331,9 @@ namespace Xamarin.Forms int index = PageController.InternalChildren.IndexOf(before); PageController.InternalChildren.Insert(index, page); + if (index == 0) + RootPage = page; + // Shouldn't be required? if (Width > 0 && Height > 0) ForceLayout(); @@ -326,15 +344,13 @@ namespace Xamarin.Forms if (((INavigationPageController)this).StackDepth == 1) return; - var root = (Page)PageController.InternalChildren.First(); - - var childrenToRemove = PageController.InternalChildren.ToArray().Where(c => c != root); - foreach (var child in childrenToRemove) + Element[] childrenToRemove = PageController.InternalChildren.Skip(1).ToArray(); + foreach (Element child in childrenToRemove) PageController.InternalChildren.Remove(child); - CurrentPage = root; + CurrentPage = RootPage; - var args = new NavigationRequestedEventArgs(root, animated); + var args = new NavigationRequestedEventArgs(RootPage, animated); EventHandler requestPopToRoot = PopToRootRequestedInternal; if (requestPopToRoot != null) @@ -345,8 +361,7 @@ namespace Xamarin.Forms await args.Task; } - if (PoppedToRoot != null) - PoppedToRoot(this, new PoppedToRootEventArgs(root, childrenToRemove.OfType().ToList())); + PoppedToRoot?.Invoke(this, new PoppedToRootEventArgs(RootPage, childrenToRemove.OfType().ToList())); } async Task PushAsyncInner(Page page, bool animated) @@ -367,24 +382,29 @@ namespace Xamarin.Forms await args.Task; } - if (Pushed != null) - Pushed(this, args); + Pushed?.Invoke(this, args); } void PushPage(Page page) { PageController.InternalChildren.Add(page); + if (PageController.InternalChildren.Count == 1) + RootPage = page; + CurrentPage = page; } void RemovePage(Page page) { - if (page == CurrentPage && ((INavigationPageController)this).StackDepth <= 1) + if (page == null) + throw new ArgumentNullException($"{nameof(page)} cannot be null."); + + if (page == CurrentPage && CurrentPage == RootPage) throw new InvalidOperationException("Cannot remove root page when it is also the currently displayed page."); if (page == CurrentPage) { - Log.Warning("NavigationPage", "RemovePage called for CurrentPage object. This can result in undesired behavior, consider called PopAsync instead."); + Log.Warning("NavigationPage", "RemovePage called for CurrentPage object. This can result in undesired behavior, consider calling PopAsync instead."); PopAsync(); return; } @@ -393,10 +413,11 @@ namespace Xamarin.Forms throw new ArgumentException("Page to remove must be contained on this Navigation Page"); EventHandler handler = RemovePageRequestedInternal; - if (handler != null) - handler(this, new NavigationRequestedEventArgs(page, true)); + handler?.Invoke(this, new NavigationRequestedEventArgs(page, true)); PageController.InternalChildren.Remove(page); + if (RootPage == page) + RootPage = (Page)PageController.InternalChildren.First(); } void SafePop() diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/NavigationPage.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/NavigationPage.xml index 1094d15..c2afced 100644 --- a/docs/Xamarin.Forms.Core/Xamarin.Forms/NavigationPage.xml +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/NavigationPage.xml @@ -226,6 +226,42 @@ + + + + Property + + 2.0.0.0 + + + Xamarin.Forms.Page + + + + The that is the root of the navigation stack. + + To be added. + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.BindableProperty + + + + Identifies the property. + + + + + -- 2.7.4