[Shell] fixes navigate to a relative URI (#4977)

This commit is contained in:
Pavel Yakovlev 2019-01-15 17:05:51 +03:00 коммит произвёл Stephane Delcroix
Родитель cc7e7eb8c2
Коммит e3360aa8c9
3 изменённых файлов: 85 добавлений и 2 удалений

Просмотреть файл

@ -127,7 +127,60 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tabfour/content/"));
}
[Test]
public async Task RelativeGoTo()
{
var shell = new Shell
{
Route = "s"
};
var one = new ShellItem { Route = "one" };
var two = new ShellItem { Route = "two" };
var tab11 = MakeSimpleShellSection("tab11", "content");
var tab12 = MakeSimpleShellSection("tab12", "content");
var tab21 = MakeSimpleShellSection("tab21", "content");
var tab22 = MakeSimpleShellSection("tab22", "content");
var tab23 = MakeSimpleShellSection("tab23", "content");
one.Items.Add(tab11);
one.Items.Add(tab12);
two.Items.Add(tab21);
two.Items.Add(tab22);
two.Items.Add(tab23);
shell.Items.Add(one);
shell.Items.Add(two);
await shell.GoToAsync("app:///s/two/tab21/");
await shell.GoToAsync("/tab22");
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tab22/content/"));
await shell.GoToAsync("tab21");
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tab21/content/"));
await shell.GoToAsync("/tab23");
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tab23/content/"));
await shell.GoToAsync("../one/tab11");
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/one/tab11/content/"));
await shell.GoToAsync("/eee/hm../../../../two/../one/../two/tab21");
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tab21/content/"));
await shell.GoToAsync(new ShellNavigationState("../one/tab11"));
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/one/tab11/content/"));
await shell.GoToAsync(new ShellNavigationState($"../two/tab23/content?{nameof(ShellTestPage.SomeQueryParameter)}=1234"));
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/two/tab23/content/"));
Assert.AreEqual("1234", (two.CurrentItem.CurrentItem.Content as ShellTestPage).SomeQueryParameter);
await shell.GoToAsync(new ShellNavigationState($"../one/tab11#fragment"));
Assert.That(shell.CurrentState.Location.ToString(), Is.EqualTo("app:///s/one/tab11/content/"));
}
[Test]
public async Task NavigationWithQueryStringWhenPageMatchesBindingContext()

Просмотреть файл

@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
@ -324,6 +325,35 @@ namespace Xamarin.Forms
public static Shell CurrentShell => Application.Current?.MainPage as Shell;
Uri GetAbsoluteUri(Uri relativeUri)
{
if (CurrentItem == null)
throw new InvalidOperationException("Relative path is used after selecting Current item.");
var parseUri = Regex.Match(relativeUri.OriginalString, @"(?<u>.+?)(\?(?<q>.+?))?(#(?<f>.+))?$").Groups;
var url = parseUri["u"].Value;
var query = parseUri["q"].Value;
var fragment = parseUri["f"].Value;
Element item = CurrentItem;
var list = new List<string> { url.Trim('/') };
while (item != null)
{
var route = Routing.GetRoute(item)?.Trim('/');
if (string.IsNullOrEmpty(route))
break;
list.Insert(0, route);
item = item.Parent;
}
var parentUriBuilder = new UriBuilder(RouteScheme)
{
Path = string.Join("/", list),
Query = query,
Fragment = fragment
};
return parentUriBuilder.Uri;
}
public async Task GoToAsync(ShellNavigationState state, bool animate = true)
{
// FIXME: This should not be none, we need to compute the delta and set flags correctly
@ -333,7 +363,7 @@ namespace Xamarin.Forms
_accumulateNavigatedEvents = true;
var uri = state.Location;
var uri = state.Location.IsAbsoluteUri ? state.Location : GetAbsoluteUri(state.Location);
var queryString = uri.Query;
var queryData = ParseQueryString(queryString);
var path = uri.AbsolutePath;

Просмотреть файл

@ -7,7 +7,7 @@ namespace Xamarin.Forms
public Uri Location { get; set; }
public ShellNavigationState() { }
public ShellNavigationState(string location) => Location = new Uri(location);
public ShellNavigationState(string location) => Location = new Uri(location, UriKind.RelativeOrAbsolute);
public ShellNavigationState(Uri location) => Location = location;
public static implicit operator ShellNavigationState(Uri uri) => new ShellNavigationState(uri);
public static implicit operator ShellNavigationState(string value) => new ShellNavigationState(value);