Fix iOS so if you remove more than one page it's able to remove them successfully (#14383)
* Fix iOS Shell when removing multiple views * - ui tests and fix navigate args * - improve logic * Update ShellSection.cs * - update UI Tests
This commit is contained in:
Родитель
0cc0a37a5d
Коммит
86db84805e
|
@ -390,7 +390,7 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
|
||||
<PackageReference Include="Xamarin.Insights" Version="1.12.3" />
|
||||
<PackageReference Include="Xamarin.TestCloud.Agent" Version="0.22.1" />
|
||||
<PackageReference Include="Xamarin.TestCloud.Agent" Version="0.22.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 13916, "[iOS] iOS Application crashes on Back press when navigated to using GoToAsync with \"//\" or \"///\" route if 2 or more things are removed from the navigation stack",
|
||||
PlatformAffected.iOS)]
|
||||
#if UITEST
|
||||
[NUnit.Framework.Category(Core.UITests.UITestCategories.Github5000)]
|
||||
[NUnit.Framework.Category(UITestCategories.Shell)]
|
||||
#endif
|
||||
public class Issue13916 : TestShell
|
||||
{
|
||||
static int pageCount = 1;
|
||||
protected override void Init()
|
||||
{
|
||||
Routing.RegisterRoute(nameof(Issue13916SuccessPage), typeof(Issue13916SuccessPage));
|
||||
|
||||
AddFlyoutItem(CreateContentPage(), "Push Me");
|
||||
}
|
||||
|
||||
|
||||
public class Issue13916SuccessPage : ContentPage
|
||||
{
|
||||
public Issue13916SuccessPage()
|
||||
{
|
||||
StackLayout layout = new StackLayout();
|
||||
Label label = new Label()
|
||||
{
|
||||
Text = "Success",
|
||||
AutomationId = "Success"
|
||||
};
|
||||
layout.Children.Add(label);
|
||||
Content = layout;
|
||||
}
|
||||
}
|
||||
|
||||
ContentPage CreateContentPage()
|
||||
{
|
||||
StackLayout layout = new StackLayout();
|
||||
Button button = new Button()
|
||||
{
|
||||
Text = "Click Me",
|
||||
AutomationId = $"ClickMe{pageCount}",
|
||||
Command = new Command(async () =>
|
||||
{
|
||||
if (Navigation.NavigationStack.Count >= 3)
|
||||
{
|
||||
await GoToAsync($"../../{nameof(Issue13916SuccessPage)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Navigation.PushAsync(CreateContentPage());
|
||||
}
|
||||
})
|
||||
};
|
||||
pageCount++;
|
||||
|
||||
layout.Children.Add(button);
|
||||
|
||||
return new ContentPage()
|
||||
{
|
||||
Content = layout
|
||||
};
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public void RemovingMoreThanOneInnerPageAndThenPushingAPageCrashes()
|
||||
{
|
||||
RunningApp.Tap("ClickMe1");
|
||||
RunningApp.Tap("ClickMe2");
|
||||
RunningApp.Tap("ClickMe3");
|
||||
RunningApp.WaitForElement("Success");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue13126.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue13126_2.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue13551.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue13916.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)RadioButtonTemplateFromStyle.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ShellSearchHandlerItemSizing.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ShellWithCustomRendererDisabledAnimations.cs" />
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.0.14" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.1.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter">
|
||||
<Version>3.17.0</Version>
|
||||
</PackageReference>
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Xamarin.Forms.Core.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ShellNavigatedArgsTests : ShellTestBase
|
||||
{
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
Routing.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RemoveInnerPagesNavigatingArgs()
|
||||
{
|
||||
Routing.RegisterRoute("SecondPageView", typeof(ContentPage));
|
||||
Routing.RegisterRoute("ThirdPageView", typeof(ContentPage));
|
||||
Routing.RegisterRoute("FourthPage", typeof(ContentPage));
|
||||
|
||||
var shell = new TestShell(CreateShellItem<FlyoutItem>(shellContentRoute: "HomePageView"));
|
||||
|
||||
await shell.GoToAsync("//HomePageView/SecondPageView/ThirdPageView");
|
||||
await shell.GoToAsync("//HomePageView/FourthPage");
|
||||
|
||||
shell.TestNavigatedArgs(ShellNavigationSource.Pop, "//HomePageView/SecondPageView/ThirdPageView", "//HomePageView/FourthPage");
|
||||
Assert.AreEqual(3, shell.NavigatedCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PopToRootSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(CreateShellItem());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PopToRootAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.PopToRoot, shell.LastShellNavigatingEventArgs.Source);
|
||||
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
|
||||
await shell.Navigation.PopAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.Pop, shell.LastShellNavigatingEventArgs.Source);
|
||||
|
||||
await shell.Navigation.PopAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.PopToRoot, shell.LastShellNavigatingEventArgs.Source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PushingSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(CreateShellItem(shellItemRoute: "item1"));
|
||||
shell.RegisterPage(nameof(PushingSetsCorrectNavigationSource));
|
||||
await shell.GoToAsync(nameof(PushingSetsCorrectNavigationSource));
|
||||
|
||||
shell.TestNavigatingArgs(ShellNavigationSource.Push,
|
||||
"//item1", $"{nameof(PushingSetsCorrectNavigationSource)}");
|
||||
|
||||
shell.TestNavigatedArgs(ShellNavigationSource.Push,
|
||||
"//item1", $"//item1/{nameof(PushingSetsCorrectNavigationSource)}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellItemSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item1"),
|
||||
CreateShellItem(shellItemRoute: "item2")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellItemChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellSectionSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellSectionRoute: "item1")
|
||||
);
|
||||
|
||||
shell.Items[0].Items.Add(CreateShellSection(shellContentRoute: "item2"));
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellSectionChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PoppingSamePageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("detailspage", typeof(ContentPage));
|
||||
var shell = new TestShell(CreateShellItem(shellItemRoute: "item1"));
|
||||
await shell.GoToAsync("detailspage/detailspage");
|
||||
await shell.Navigation.PopAsync();
|
||||
|
||||
|
||||
shell.TestNavigatingArgs(ShellNavigationSource.Pop,
|
||||
"//item1/detailspage/detailspage", $"..");
|
||||
|
||||
shell.TestNavigatedArgs(ShellNavigationSource.Pop,
|
||||
"//item1/detailspage/detailspage", $"//item1/detailspage");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellContentSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellContentRoute: "item1")
|
||||
);
|
||||
|
||||
shell.Items[0].Items[0].Items.Add(CreateShellContent(shellContentRoute: "item2"));
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellContentChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InsertPageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/page");
|
||||
await shell.GoToAsync("//item/pagemiddle/page");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Insert,
|
||||
"//item/page", "//item/pagemiddle/page");
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task InsertPageFromINavigationSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/page");
|
||||
ContentPage contentPage = new ContentPage();
|
||||
Routing.SetRoute(contentPage, "pagemiddle");
|
||||
shell.Navigation.InsertPageBefore(contentPage, shell.Navigation.NavigationStack.Last());
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Insert,
|
||||
"//item/page", "//item/pagemiddle/page");
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task RemovePageFromINavigationSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/pagemiddle/page");
|
||||
shell.Navigation.RemovePage(shell.Navigation.NavigationStack[1]);
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Remove,
|
||||
"//item/pagemiddle/page", "//item/page");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RemovePageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/pagemiddle/page");
|
||||
await shell.GoToAsync("//item/page");
|
||||
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Remove,
|
||||
"//item/pagemiddle/page", "//item/page");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InitialNavigatingArgs()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellItemChanged,
|
||||
null, "//item");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -488,22 +488,6 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
Assert.AreEqual(3, tab.NavigationsFired.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PoppingSamePageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("detailspage", typeof(ContentPage));
|
||||
var shell = new TestShell(CreateShellItem(shellItemRoute: "item1"));
|
||||
await shell.GoToAsync("detailspage/detailspage");
|
||||
await shell.Navigation.PopAsync();
|
||||
|
||||
|
||||
shell.TestNavigatingArgs(ShellNavigationSource.Pop,
|
||||
"//item1/detailspage/detailspage", $"..");
|
||||
|
||||
shell.TestNavigatedArgs(ShellNavigationSource.Pop,
|
||||
"//item1/detailspage/detailspage", $"//item1/detailspage");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PoppingSetsCorrectNavigationSource()
|
||||
{
|
||||
|
@ -522,127 +506,6 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
"//item1/page1/page2", $"//item1/page1");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PopToRootSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(CreateShellItem());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PopToRootAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.PopToRoot, shell.LastShellNavigatingEventArgs.Source);
|
||||
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
await shell.Navigation.PushAsync(new ContentPage());
|
||||
|
||||
await shell.Navigation.PopAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.Pop, shell.LastShellNavigatingEventArgs.Source);
|
||||
|
||||
await shell.Navigation.PopAsync();
|
||||
Assert.AreEqual(ShellNavigationSource.PopToRoot, shell.LastShellNavigatingEventArgs.Source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PushingSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(CreateShellItem(shellItemRoute: "item1"));
|
||||
shell.RegisterPage(nameof(PushingSetsCorrectNavigationSource));
|
||||
await shell.GoToAsync(nameof(PushingSetsCorrectNavigationSource));
|
||||
|
||||
shell.TestNavigatingArgs(ShellNavigationSource.Push,
|
||||
"//item1", $"{nameof(PushingSetsCorrectNavigationSource)}");
|
||||
|
||||
shell.TestNavigatedArgs(ShellNavigationSource.Push,
|
||||
"//item1", $"//item1/{nameof(PushingSetsCorrectNavigationSource)}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellItemSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item1"),
|
||||
CreateShellItem(shellItemRoute: "item2")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellItemChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellSectionSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellSectionRoute: "item1")
|
||||
);
|
||||
|
||||
shell.Items[0].Items.Add(CreateShellSection(shellContentRoute: "item2"));
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellSectionChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangingShellContentSetsCorrectNavigationSource()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellContentRoute: "item1")
|
||||
);
|
||||
|
||||
shell.Items[0].Items[0].Items.Add(CreateShellContent(shellContentRoute: "item2"));
|
||||
|
||||
await shell.GoToAsync("//item2");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellContentChanged,
|
||||
"//item1", "//item2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InsertPageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/page");
|
||||
await shell.GoToAsync("//item/pagemiddle/page");
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Insert,
|
||||
"//item/page", "//item/pagemiddle/page");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RemovePageSetsCorrectNavigationSource()
|
||||
{
|
||||
Routing.RegisterRoute("pagemiddle", typeof(ContentPage));
|
||||
Routing.RegisterRoute("page", typeof(ContentPage));
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
await shell.GoToAsync("//item/pagemiddle/page");
|
||||
await shell.GoToAsync("//item/page");
|
||||
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.Remove,
|
||||
"//item/pagemiddle/page", "//item/page");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InitialNavigatingArgs()
|
||||
{
|
||||
var shell = new TestShell(
|
||||
CreateShellItem(shellItemRoute: "item")
|
||||
);
|
||||
|
||||
shell.TestNavigationArgs(ShellNavigationSource.ShellItemChanged,
|
||||
null, "//item");
|
||||
}
|
||||
|
||||
|
||||
[TestCase(true, 2)]
|
||||
[TestCase(false, 2)]
|
||||
|
|
|
@ -374,8 +374,6 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
OnNavigatingCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void TestNavigationArgs(ShellNavigationSource source, string from, string to)
|
||||
{
|
||||
TestNavigatingArgs(source, from, to);
|
||||
|
@ -392,6 +390,7 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
Assert.AreEqual(from, this.LastShellNavigatedEventArgs.Previous.Location.ToString());
|
||||
|
||||
Assert.AreEqual(to, this.LastShellNavigatedEventArgs.Current.Location.ToString());
|
||||
Assert.AreEqual(to, this.CurrentState.Location.ToString());
|
||||
}
|
||||
|
||||
public void TestNavigatingArgs(ShellNavigationSource source, string from, string to)
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
<Compile Include="ShellFlyoutItemGroupTests.cs" />
|
||||
<Compile Include="ShellFlyoutItemTemplateTests.cs" />
|
||||
<Compile Include="ShellModalTests.cs" />
|
||||
<Compile Include="ShellNavigatedArgsTests.cs" />
|
||||
<Compile Include="ShellNavigationStateTests.cs" />
|
||||
<Compile Include="ShellNavigatingTests.cs" />
|
||||
<Compile Include="ShellTestBase.cs" />
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<PackageReference Include="Selenium.Support" Version="3.141.0" />
|
||||
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
|
||||
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.0.14" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.1.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter">
|
||||
<Version>3.17.0</Version>
|
||||
</PackageReference>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.0.14" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.1.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter">
|
||||
<Version>3.17.0</Version>
|
||||
</PackageReference>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<PackageReference Include="ServiceStack.Interfaces" Version="4.5.12" />
|
||||
<PackageReference Include="ServiceStack.Text" Version="4.5.12" />
|
||||
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.0.14" />
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.1.0" />
|
||||
<PackageReference Include="Xamarin.UITest.Desktop" Version="0.0.7" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -468,10 +468,13 @@ namespace Xamarin.Forms
|
|||
var modalStack = shellSection?.Navigation?.ModalStack;
|
||||
var result = ShellNavigationManager.GetNavigationState(shellItem, shellSection, shellContent, stack, modalStack);
|
||||
|
||||
SetValueFromRenderer(CurrentStatePropertyKey, result);
|
||||
|
||||
_navigationManager.HandleNavigated(new ShellNavigatedEventArgs(oldState, CurrentState, source));
|
||||
if (result?.Location != oldState?.Location)
|
||||
{
|
||||
SetValueFromRenderer(CurrentStatePropertyKey, result);
|
||||
_navigationManager.HandleNavigated(new ShellNavigatedEventArgs(oldState, CurrentState, source));
|
||||
}
|
||||
}
|
||||
|
||||
ReadOnlyCollection<ShellItem> IShellController.GetItems() =>
|
||||
new ReadOnlyCollection<ShellItem>(((ShellItemCollection)Items).VisibleItemsReadOnly.ToList());
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Xamarin.Forms
|
|||
readonly Shell _shell;
|
||||
ShellNavigatedEventArgs _accumulatedEvent;
|
||||
bool _accumulateNavigatedEvents;
|
||||
|
||||
public bool AccumulateNavigatedEvents => _accumulateNavigatedEvents;
|
||||
public event EventHandler<ShellNavigatedEventArgs> Navigated;
|
||||
public event EventHandler<ShellNavigatingEventArgs> Navigating;
|
||||
|
||||
|
@ -166,6 +166,7 @@ namespace Xamarin.Forms
|
|||
await _shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, queryData, animate, isRelativePopping);
|
||||
}
|
||||
|
||||
(_shell as IShellController).UpdateCurrentState(source);
|
||||
_accumulateNavigatedEvents = false;
|
||||
|
||||
// this can be null in the event that no navigation actually took place!
|
||||
|
|
|
@ -116,7 +116,6 @@ namespace Xamarin.Forms
|
|||
await poppingCompleted;
|
||||
|
||||
RemovePage(page);
|
||||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
}
|
||||
|
||||
async void IShellSectionController.SendPoppingToRoot(Task finishedPopping)
|
||||
|
@ -135,8 +134,6 @@ namespace Xamarin.Forms
|
|||
|
||||
for (int i = 1; i < oldStack.Count; i++)
|
||||
RemovePage(oldStack[i]);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.PopToRoot);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
|
@ -151,8 +148,6 @@ namespace Xamarin.Forms
|
|||
_navStack.Remove(last);
|
||||
|
||||
RemovePage(last);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
}
|
||||
|
||||
// we want the list returned from here to remain point in time accurate
|
||||
|
@ -178,7 +173,6 @@ namespace Xamarin.Forms
|
|||
_navStack.Remove(page);
|
||||
|
||||
RemovePage(page);
|
||||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
}
|
||||
|
||||
|
||||
|
@ -572,7 +566,7 @@ namespace Xamarin.Forms
|
|||
|
||||
if (Parent?.Parent is IShellController shell)
|
||||
{
|
||||
shell.UpdateCurrentState(ShellNavigationSource.ShellSectionChanged);
|
||||
//shell.UpdateCurrentState(ShellNavigationSource.ShellSectionChanged);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,8 +718,6 @@ namespace Xamarin.Forms
|
|||
};
|
||||
|
||||
_navigationRequested?.Invoke(this, args);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.Insert);
|
||||
}
|
||||
|
||||
protected async virtual Task<Page> OnPopAsync(bool animated)
|
||||
|
@ -762,8 +754,6 @@ namespace Xamarin.Forms
|
|||
await args.Task;
|
||||
RemovePage(page);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
|
@ -804,7 +794,6 @@ namespace Xamarin.Forms
|
|||
}
|
||||
|
||||
PresentedPageAppearing();
|
||||
SendUpdateCurrentState(ShellNavigationSource.PopToRoot);
|
||||
}
|
||||
|
||||
protected virtual Task OnPushAsync(Page page, bool animated)
|
||||
|
@ -834,8 +823,6 @@ namespace Xamarin.Forms
|
|||
AddPage(page);
|
||||
_navigationRequested?.Invoke(this, args);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.Push);
|
||||
|
||||
if (args.Task == null)
|
||||
return Task.FromResult(true);
|
||||
return args.Task;
|
||||
|
@ -867,8 +854,6 @@ namespace Xamarin.Forms
|
|||
bool isAnimated = animated ?? (Shell.GetPresentationMode(pageToPop) & PresentationMode.NotAnimated) != PresentationMode.NotAnimated;
|
||||
await Navigation.PopModalAsync(isAnimated);
|
||||
}
|
||||
|
||||
((IShellController)Shell).UpdateCurrentState(ShellNavigationSource.ShellSectionChanged);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -911,8 +896,6 @@ namespace Xamarin.Forms
|
|||
RequestType = NavigationRequestType.Remove
|
||||
};
|
||||
_navigationRequested?.Invoke(this, args);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.Remove);
|
||||
}
|
||||
|
||||
internal bool IsVisibleSection => Parent?.Parent is Shell shell && shell.CurrentItem?.CurrentItem == this;
|
||||
|
@ -1013,14 +996,6 @@ namespace Xamarin.Forms
|
|||
|
||||
void SendAppearanceChanged() => ((IShellController)Parent?.Parent)?.AppearanceChanged(this, false);
|
||||
|
||||
void SendUpdateCurrentState(ShellNavigationSource source)
|
||||
{
|
||||
if (Parent?.Parent is IShellController shell)
|
||||
{
|
||||
shell.UpdateCurrentState(source);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
|
@ -1051,8 +1026,6 @@ namespace Xamarin.Forms
|
|||
|
||||
protected override IReadOnlyList<Page> GetNavigationStack() => _owner.GetNavigationStack();
|
||||
|
||||
protected override void OnInsertPageBefore(Page page, Page before) => _owner.OnInsertPageBefore(page, before);
|
||||
|
||||
protected override async Task<Page> OnPopAsync(bool animated)
|
||||
{
|
||||
if (!_owner.IsVisibleSection)
|
||||
|
@ -1116,7 +1089,64 @@ namespace Xamarin.Forms
|
|||
return _owner.Shell.NavigationManager.GoToAsync(navigationParameters);
|
||||
}
|
||||
|
||||
protected override void OnRemovePage(Page page) => _owner.OnRemovePage(page);
|
||||
protected override void OnRemovePage(Page page)
|
||||
{
|
||||
if (!_owner.IsVisibleSection || _owner.Shell.NavigationManager.AccumulateNavigatedEvents)
|
||||
{
|
||||
_owner.OnRemovePage(page);
|
||||
return;
|
||||
}
|
||||
|
||||
var stack = _owner.Stack.ToList();
|
||||
stack.Remove(page);
|
||||
var navigationState = GetUpdatedStatus(stack);
|
||||
|
||||
ShellNavigatingEventArgs shellNavigatingEventArgs = new ShellNavigatingEventArgs(
|
||||
_owner.Shell.CurrentState,
|
||||
navigationState.Location,
|
||||
ShellNavigationSource.Remove,
|
||||
false);
|
||||
|
||||
_owner.Shell.NavigationManager.HandleNavigating(shellNavigatingEventArgs);
|
||||
_owner.OnRemovePage(page);
|
||||
(_owner.Shell as IShellController).UpdateCurrentState(ShellNavigationSource.Remove);
|
||||
}
|
||||
|
||||
protected override void OnInsertPageBefore(Page page, Page before)
|
||||
{
|
||||
if (!_owner.IsVisibleSection || _owner.Shell.NavigationManager.AccumulateNavigatedEvents)
|
||||
{
|
||||
_owner.OnInsertPageBefore(page, before);
|
||||
return;
|
||||
}
|
||||
|
||||
var stack = _owner.Stack.ToList();
|
||||
var index = stack.IndexOf(before);
|
||||
if (index == -1)
|
||||
throw new ArgumentException("Page not found in nav stack");
|
||||
|
||||
stack.Insert(index, page);
|
||||
var navigationState = GetUpdatedStatus(stack);
|
||||
|
||||
ShellNavigatingEventArgs shellNavigatingEventArgs = new ShellNavigatingEventArgs(
|
||||
_owner.Shell.CurrentState,
|
||||
navigationState.Location,
|
||||
ShellNavigationSource.Insert,
|
||||
false);
|
||||
|
||||
_owner.Shell.NavigationManager.HandleNavigating(shellNavigatingEventArgs);
|
||||
_owner.OnInsertPageBefore(page, before);
|
||||
(_owner.Shell as IShellController).UpdateCurrentState(ShellNavigationSource.Insert);
|
||||
}
|
||||
|
||||
ShellNavigationState GetUpdatedStatus(IReadOnlyList<Page> stack)
|
||||
{
|
||||
var shellItem = _owner.Shell.CurrentItem;
|
||||
var shellSection = shellItem?.CurrentItem;
|
||||
var shellContent = shellSection?.CurrentItem;
|
||||
var modalStack = shellSection?.Navigation?.ModalStack;
|
||||
return ShellNavigationManager.GetNavigationState(shellItem, shellSection, shellContent, stack, modalStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,19 +68,33 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
ShellSection _shellSection;
|
||||
bool _ignorePopCall;
|
||||
|
||||
// When setting base.ViewControllers iOS doesn't modify the property right away.
|
||||
// if you set base.ViewControllers to a new array and then retrieve base.ViewControllers
|
||||
// iOS will return the previous array until the new array has been processed
|
||||
// This means if you try to remove one VC and then try to remove a second VC before the first one is processed
|
||||
// you'll end up re-adding back the first VC
|
||||
// ViewControllers = ViewControllers.Remove(vc1)
|
||||
// ViewControllers = ViewControllers.Remove(vc2)
|
||||
// You've now added vc1 back because the second call to ViewControllers will still return a ViewControllers list with vc1 in it
|
||||
UIViewController[] _pendingViewControllers;
|
||||
|
||||
public ShellSectionRenderer(IShellContext context) : base()
|
||||
{
|
||||
Delegate = new NavDelegate(this);
|
||||
_context = context;
|
||||
_context.Shell.PropertyChanged += HandleShellPropertyChanged;
|
||||
_context.Shell.Navigated += OnNavigated;
|
||||
_context.Shell.Navigating += OnNavigating;
|
||||
}
|
||||
|
||||
public ShellSectionRenderer(IShellContext context, Type navigationBarType, Type toolbarType)
|
||||
public ShellSectionRenderer(IShellContext context, Type navigationBarType, Type toolbarType)
|
||||
: base(navigationBarType, toolbarType)
|
||||
{
|
||||
Delegate = new NavDelegate(this);
|
||||
_context = context;
|
||||
_context.Shell.PropertyChanged += HandleShellPropertyChanged;
|
||||
_context.Shell.Navigated += OnNavigated;
|
||||
_context.Shell.Navigating += OnNavigating;
|
||||
}
|
||||
|
||||
[Export("navigationBar:shouldPopItem:")]
|
||||
|
@ -89,14 +103,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
SendPop();
|
||||
|
||||
internal bool SendPop()
|
||||
{
|
||||
{
|
||||
// this means the pop is already done, nothing we can do
|
||||
if (ViewControllers.Length < NavigationBar.Items.Length)
|
||||
if (ActiveViewControllers().Length < NavigationBar.Items.Length)
|
||||
return true;
|
||||
|
||||
foreach(var tracker in _trackers)
|
||||
foreach (var tracker in _trackers)
|
||||
{
|
||||
if(tracker.Value.ViewController == TopViewController)
|
||||
if (tracker.Value.ViewController == TopViewController)
|
||||
{
|
||||
var behavior = Shell.GetBackButtonBehavior(tracker.Value.Page);
|
||||
var command = behavior.GetPropertyIfSet<ICommand>(BackButtonBehavior.CommandProperty, null);
|
||||
|
@ -104,7 +118,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (command != null)
|
||||
{
|
||||
if(command.CanExecute(commandParameter))
|
||||
if (command.CanExecute(commandParameter))
|
||||
{
|
||||
command.Execute(commandParameter);
|
||||
}
|
||||
|
@ -202,6 +216,8 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
if (_context.Shell != null)
|
||||
{
|
||||
_context.Shell.PropertyChanged -= HandleShellPropertyChanged;
|
||||
_context.Shell.Navigated -= OnNavigated;
|
||||
_context.Shell.Navigating -= OnNavigating;
|
||||
((IShellController)_context.Shell).RemoveAppearanceObserver(this);
|
||||
}
|
||||
|
||||
|
@ -263,7 +279,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
_renderer = CreateShellSectionRootRenderer(ShellSection, _context);
|
||||
|
||||
PushViewController(_renderer.ViewController, false);
|
||||
|
||||
|
||||
var stack = ShellSection.Stack;
|
||||
for (int i = 1; i < stack.Count; i++)
|
||||
{
|
||||
|
@ -307,7 +323,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
_trackers[page] = tracker;
|
||||
|
||||
ViewControllers.Insert(ViewControllers.IndexOf(beforeRenderer.ViewController), renderer.ViewController);
|
||||
InsertViewController(ActiveViewControllers().IndexOf(beforeRenderer.ViewController), renderer.ViewController);
|
||||
}
|
||||
|
||||
protected virtual void OnNavigationRequested(object sender, NavigationRequestedEventArgs e)
|
||||
|
@ -353,7 +369,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override UIViewController[] PopToRootViewController(bool animated)
|
||||
{
|
||||
if (!_ignorePopCall && ViewControllers.Length > 1)
|
||||
if (!_ignorePopCall && ActiveViewControllers().Length > 1)
|
||||
{
|
||||
ProcessPopToRoot();
|
||||
}
|
||||
|
@ -432,9 +448,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
OnPopRequested(e);
|
||||
}
|
||||
|
||||
if(ViewControllers.Contains(viewController))
|
||||
ViewControllers = ViewControllers.Remove(viewController);
|
||||
|
||||
RemoveViewController(viewController);
|
||||
DisposePage(page);
|
||||
}
|
||||
}
|
||||
|
@ -461,8 +475,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
if (_trackers.TryGetValue(page, out var tracker))
|
||||
{
|
||||
if(!calledFromDispose && tracker.ViewController != null && ViewControllers.Contains(tracker.ViewController))
|
||||
ViewControllers = ViewControllers.Remove(_trackers[page].ViewController);
|
||||
if (!calledFromDispose && tracker.ViewController != null && ActiveViewControllers().Contains(tracker.ViewController))
|
||||
{
|
||||
System.Diagnostics.Debug.Write($"Disposing {_trackers[page].ViewController.GetHashCode()}");
|
||||
RemoveViewController(_trackers[page].ViewController);
|
||||
}
|
||||
|
||||
tracker.Dispose();
|
||||
_trackers.Remove(page);
|
||||
|
@ -502,6 +519,70 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
UpdateNavigationBarHasShadow();
|
||||
}
|
||||
|
||||
// We only care about using pendingViewControllers when we are setting the ViewControllers array directly
|
||||
// So, once navigation starts again (or ends) we can just clear the pendingViewControllers
|
||||
void OnNavigating(object sender, ShellNavigatingEventArgs e)
|
||||
{
|
||||
_pendingViewControllers = null;
|
||||
}
|
||||
|
||||
void OnNavigated(object sender, ShellNavigatedEventArgs e)
|
||||
{
|
||||
_pendingViewControllers = null;
|
||||
}
|
||||
|
||||
// These are all just safety nets to ensure that _pendingViewControllers doesn't for some reason get out of sync
|
||||
// and start causing issues. In theory we could just override ViewControllers here to make sure _pendingViewControllers
|
||||
// stays in sync but I don't trust that `ViewControllers.set` is reliably called with every modification
|
||||
public override UIViewController[] ViewControllers
|
||||
{
|
||||
get => base.ViewControllers;
|
||||
set
|
||||
{
|
||||
if (_pendingViewControllers != null)
|
||||
_pendingViewControllers = value;
|
||||
|
||||
base.ViewControllers = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override UIViewController[] PopToViewController(UIViewController viewController, bool animated)
|
||||
{
|
||||
_pendingViewControllers = null;
|
||||
return base.PopToViewController(viewController, animated);
|
||||
}
|
||||
|
||||
public override void PushViewController(UIViewController viewController, bool animated)
|
||||
{
|
||||
_pendingViewControllers = null;
|
||||
base.PushViewController(viewController, animated);
|
||||
}
|
||||
|
||||
public override UIViewController PopViewController(bool animated)
|
||||
{
|
||||
_pendingViewControllers = null;
|
||||
return base.PopViewController(animated);
|
||||
}
|
||||
|
||||
UIViewController[] ActiveViewControllers() =>
|
||||
_pendingViewControllers ?? base.ViewControllers;
|
||||
|
||||
void RemoveViewController(UIViewController viewController)
|
||||
{
|
||||
_pendingViewControllers = _pendingViewControllers ?? base.ViewControllers;
|
||||
if (_pendingViewControllers.Contains(viewController))
|
||||
_pendingViewControllers = _pendingViewControllers.Remove(viewController);
|
||||
|
||||
ViewControllers = _pendingViewControllers;
|
||||
}
|
||||
|
||||
void InsertViewController(int index, UIViewController viewController)
|
||||
{
|
||||
_pendingViewControllers = _pendingViewControllers ?? base.ViewControllers;
|
||||
_pendingViewControllers = _pendingViewControllers.Insert(index, viewController);
|
||||
ViewControllers = _pendingViewControllers;
|
||||
}
|
||||
|
||||
void PushPage(Page page, bool animated, TaskCompletionSource<bool> completionSource = null)
|
||||
{
|
||||
var renderer = Platform.CreateRenderer(page);
|
||||
|
@ -576,7 +657,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override bool ShouldBegin(UIGestureRecognizer recognizer)
|
||||
{
|
||||
if (_parent.ViewControllers.Length == 1)
|
||||
if ((_parent as ShellSectionRenderer).ActiveViewControllers().Length == 1)
|
||||
return false;
|
||||
return _shouldPop();
|
||||
}
|
||||
|
@ -619,6 +700,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override void WillShowViewController(UINavigationController navigationController, [Transient] UIViewController viewController, bool animated)
|
||||
{
|
||||
System.Diagnostics.Debug.Write($"WillShowViewController {viewController.GetHashCode()}");
|
||||
var element = _self.ElementForViewController(viewController);
|
||||
|
||||
bool navBarVisible;
|
||||
|
|
Загрузка…
Ссылка в новой задаче