diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml
new file mode 100644
index 00000000000..67b894f3b07
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml.cs
new file mode 100644
index 00000000000..e22a71dc244
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11653.xaml.cs
@@ -0,0 +1,36 @@
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Shapes;
+using System.Collections.Generic;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.Shape)]
+#endif
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 11653,
+ "[Bug] Polygon.Points doesn't respond to CollectionChanged events",
+ PlatformAffected.All)]
+ public partial class Issue11653 : TestContentPage
+ {
+ public Issue11653()
+ {
+#if APP
+ Device.SetFlags(new List { ExperimentalFlags.BrushExperimental, ExperimentalFlags.ShapesExperimental });
+ InitializeComponent();
+#endif
+ }
+
+ protected override void Init()
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11723.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11723.cs
new file mode 100644
index 00000000000..19b65e82a2b
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11723.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+using System.Linq;
+
+
+#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, 11723, "[Bug] ContentPage in NavigationStack misplaced initially",
+ PlatformAffected.iOS)]
+#if UITEST
+ [NUnit.Framework.Category(Core.UITests.UITestCategories.Github10000)]
+ [NUnit.Framework.Category(UITestCategories.Shell)]
+#endif
+ public class Issue11723 : TestShell
+ {
+ int labelIndex = 0;
+ ContentPage CreateContentPage()
+ {
+ var page = new ContentPage()
+ {
+ Content = new StackLayout()
+ {
+ Children =
+ {
+ new Label()
+ {
+ Text = "As you navigate this text should show up in the correct spot. If it's hidden and then shows up this test has failed.",
+ AutomationId = $"InitialText{labelIndex}"
+ },
+ new Button()
+ {
+ Text = "Push Page",
+ AutomationId = "PushPage",
+ Command = new Command(async () =>
+ {
+ labelIndex++;
+ await Navigation.PushAsync(CreateContentPage());
+ })
+ },
+ new Button()
+ {
+ Text = "Pop Page",
+ AutomationId = "PopPage",
+ Command = new Command(async () =>
+ {
+ labelIndex--;
+ await Navigation.PopAsync();
+ })
+ }
+ }
+ }
+ };
+
+ SetNavBarIsVisible(page, false);
+ PlatformConfiguration.iOSSpecific.Page.SetUseSafeArea(page, true);
+
+ return page;
+ }
+
+ protected override void Init()
+ {
+ AddContentPage(CreateContentPage());
+ }
+
+
+#if UITEST
+ [Test]
+ public void PaddingIsSetOnPageBeforeItsVisible()
+ {
+ var initialTextPosition = RunningApp.WaitForFirstElement($"InitialText0").Rect;
+ RunningApp.Tap("PushPage");
+ CompareTextLocation(initialTextPosition, 1);
+ RunningApp.Tap("PushPage");
+ CompareTextLocation(initialTextPosition, 2);
+ RunningApp.Tap("PushPage");
+ CompareTextLocation(initialTextPosition, 3);
+ RunningApp.Tap("PopPage");
+ CompareTextLocation(initialTextPosition, 2);
+ RunningApp.Tap("PopPage");
+ CompareTextLocation(initialTextPosition, 1);
+
+ }
+
+ void CompareTextLocation(UITest.Queries.AppRect initialRect, int i)
+ {
+ var newRect = RunningApp.WaitForFirstElement($"InitialText{i}").Rect;
+
+ Assert.AreEqual(newRect.X, initialRect.X, $"Error With Test :{i}");
+ Assert.AreEqual(newRect.Y, initialRect.Y, $"Error With Test :{i}");
+ Assert.AreEqual(newRect.CenterX, initialRect.CenterX, $"Error With Test :{i}");
+ Assert.AreEqual(newRect.CenterY, initialRect.CenterY, $"Error With Test :{i}");
+ }
+#endif
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11865.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11865.cs
new file mode 100644
index 00000000000..8084f5e4665
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11865.cs
@@ -0,0 +1,80 @@
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.CustomAttributes;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.SearchBar)]
+#endif
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 11865,
+ "iOS SearchBarRenderer throws a NullReferenceException when the SearchButton redirects to a new page",
+ PlatformAffected.iOS)]
+ public class Issue11865 : TestContentPage
+ {
+ public Issue11865()
+ {
+ }
+
+ protected override void Init()
+ {
+ Title = "Issue 11865";
+
+ var layout = new StackLayout
+ {
+ BackgroundColor = Color.LightGreen
+ };
+
+ var instructions = new Label
+ {
+ Padding = 12,
+ BackgroundColor = Color.Black,
+ TextColor = Color.White,
+ Text = "Type something in the SearchBar and tap the search button."
+ };
+
+ var searchBar = new SearchBar();
+
+ layout.Children.Add(instructions);
+ layout.Children.Add(searchBar);
+
+ Content = layout;
+
+ searchBar.SearchButtonPressed += (sender, args) =>
+ {
+ Application.Current.MainPage = new Issue11865SecondPage();
+ };
+ }
+ }
+
+ [Preserve(AllMembers = true)]
+ public class Issue11865SecondPage : ContentPage
+ {
+ public Issue11865SecondPage()
+ {
+ var layout = new StackLayout
+ {
+ BackgroundColor = Color.LightCoral
+ };
+
+ var instructions = new Label
+ {
+ Padding = 12,
+ BackgroundColor = Color.Black,
+ TextColor = Color.White,
+ Text = "If you can read this message (after changing the MainPage), the test has passed.",
+ Margin = new Thickness(0, 36, 0, 0)
+ };
+
+ layout.Children.Add(instructions);
+
+ Content = layout;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11869.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11869.cs
new file mode 100644
index 00000000000..2e9cbb1709f
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11869.cs
@@ -0,0 +1,121 @@
+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, 11869, "[Bug] ShellContent.IsVisible issue on Android",
+ PlatformAffected.Android)]
+#if UITEST
+ [NUnit.Framework.Category(Core.UITests.UITestCategories.Github10000)]
+ [NUnit.Framework.Category(UITestCategories.Shell)]
+#endif
+ public class Issue11869 : TestShell
+ {
+ protected override void Init()
+ {
+ ContentPage contentPage = new ContentPage();
+ var tabbar = AddContentPage(contentPage, title: "Tab 1");
+ AddBottomTab("Tab 2");
+ AddBottomTab("Tab 3");
+ AddTopTab("TopTab2");
+ AddTopTab("TopTab3");
+
+ contentPage.Content =
+ new StackLayout()
+ {
+ Children =
+ {
+ new Button
+ {
+ Text = "Hide Bottom Tab 2",
+ Command = new Command(() =>
+ {
+ Items[0].Items[1].Items[0].IsVisible = false;
+ }),
+ AutomationId = "HideBottom2"
+ },
+ new Button
+ {
+ Text = "Hide Bottom Tab 3",
+ Command = new Command(() =>
+ {
+ Items[0].Items[2].Items[0].IsVisible = false;
+ }),
+ AutomationId = "HideBottom3"
+ },
+ new Button
+ {
+ Text = "Hide Top Tab 2",
+ Command = new Command(() =>
+ {
+ Items[0].Items[0].Items[1].IsVisible = false;
+ }),
+ AutomationId = "HideTop2"
+ },
+ new Button
+ {
+ Text = "Hide Top Tab 3",
+ Command = new Command(() =>
+ {
+ Items[0].Items[0].Items[2].IsVisible = false;
+ }),
+ AutomationId = "HideTop3"
+ },
+ new Button
+ {
+ Text = "Show All Tabs",
+ Command = new Command(() =>
+ {
+ Items[0].Items[1].Items[0].IsVisible = true;
+ Items[0].Items[2].Items[0].IsVisible = true;
+ Items[0].Items[0].Items[1].IsVisible = true;
+ Items[0].Items[0].Items[2].IsVisible = true;
+ }),
+ AutomationId = "ShowAllTabs"
+ }
+ }
+ };
+ }
+
+
+#if UITEST && __SHELL__
+ [Test]
+ public void IsVisibleWorksForShowingHidingTabs()
+ {
+ RunningApp.WaitForElement("TopTab2");
+ RunningApp.Tap("HideTop2");
+ RunningApp.WaitForNoElement("TopTab2");
+
+ RunningApp.WaitForElement("TopTab3");
+ RunningApp.Tap("HideTop3");
+ RunningApp.WaitForNoElement("TopTab3");
+
+ RunningApp.WaitForElement("Tab 2");
+ RunningApp.Tap("HideBottom2");
+ RunningApp.WaitForNoElement("Tab 2");
+
+ RunningApp.WaitForElement("Tab 3");
+ RunningApp.Tap("HideBottom3");
+ RunningApp.WaitForNoElement("Tab 3");
+
+ RunningApp.Tap("ShowAllTabs");
+ RunningApp.WaitForElement("TopTab2");
+ RunningApp.WaitForElement("TopTab3");
+ RunningApp.WaitForElement("Tab 2");
+ RunningApp.WaitForElement("Tab 3");
+ }
+#endif
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/ShellStoreTests.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/ShellStoreTests.cs
new file mode 100644
index 00000000000..d557167af15
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/ShellStoreTests.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System.Linq;
+using Xamarin.Forms.PlatformConfiguration;
+using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
+using System.Threading;
+using System.ComponentModel;
+
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+#if UITEST
+ [NUnit.Framework.Category(UITestCategories.Shell)]
+#endif
+ public class ShellStoreTests
+ {
+#if UITEST
+
+ IApp RunningApp;
+ [SetUp]
+ public void ShellStoreSetup()
+ {
+ RunningApp = AppSetup.Setup();
+ if (RunningApp.Query("SwapRoot - Store Shell").Length > 0)
+ RunningApp.Tap("SwapRoot - Store Shell");
+ else
+ RunningApp.NavigateTo("SwapRoot - Store Shell");
+
+ RunningApp.WaitForElement("Welcome to the HomePage");
+ }
+
+ [Test]
+ public void LoadsWithoutCrashing()
+ {
+ RunningApp.WaitForElement("Welcome to the HomePage");
+ }
+#endif
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 1e3ea2c0810..56714f39af9 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -824,6 +824,7 @@
Issue6698View2.xaml
Code
+
@@ -1472,6 +1473,10 @@
+
+
+
+
@@ -1741,6 +1746,9 @@
MSBuild:UpdateDesignTimeXaml
+
+ MSBuild:UpdateDesignTimeXaml
+
diff --git a/Xamarin.Forms.Controls/CoreGallery.cs b/Xamarin.Forms.Controls/CoreGallery.cs
index 045c6bba0e2..3fe0d822d96 100644
--- a/Xamarin.Forms.Controls/CoreGallery.cs
+++ b/Xamarin.Forms.Controls/CoreGallery.cs
@@ -29,6 +29,7 @@ public static class Messages
{
public const string ChangeRoot = "com.xamarin.ChangeRoot";
}
+
[Preserve(AllMembers = true)]
internal class CoreCarouselPage : CarouselPage
{
@@ -39,16 +40,20 @@ public CoreCarouselPage()
Children.Add(new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "Page 2" });
}
}
+
[Preserve(AllMembers = true)]
internal class CoreContentPage : ContentPage
{
+ public CoreRootView CoreRootView { get; }
public CoreContentPage()
{
On().SetUseSafeArea(true);
AutomationId = "ContentPageRoot";
- Content = new StackLayout { Children = { new CoreRootView(), new CorePageView(this, NavigationBehavior.PushModalAsync) } };
+ CoreRootView = new CoreRootView();
+ Content = new StackLayout { Children = { CoreRootView, new CorePageView(this, NavigationBehavior.PushModalAsync) } };
}
}
+
[Preserve(AllMembers = true)]
internal class CoreMasterDetailPage : MasterDetailPage
{
@@ -522,16 +527,17 @@ async Task PushPage(Page contentPage)
}
readonly Dictionary _titleToPage;
- public async Task PushPage(string pageTitle)
+ public async Task PushPage(string pageTitle)
{
GalleryPageFactory pageFactory = null;
if (!_titleToPage.TryGetValue(pageTitle, out pageFactory))
- return;
+ return false;
var page = pageFactory.Realize();
await PushPage(page);
+ return true;
}
public void FilterPages(string filter)
@@ -545,6 +551,8 @@ public void FilterPages(string filter)
[Preserve(AllMembers = true)]
internal class CoreRootPage : ContentPage
{
+ CoreRootView CoreRootView { get; }
+
public CoreRootPage(Page rootPage, NavigationBehavior navigationBehavior = NavigationBehavior.PushAsync)
{
ValidateRegistrar();
@@ -573,7 +581,19 @@ public CoreRootPage(Page rootPage, NavigationBehavior navigationBehavior = Navig
Command = new Command(async () =>
{
if (!string.IsNullOrEmpty(searchBar.Text))
- await corePageView.PushPage(searchBar.Text);
+ {
+ if(!(await corePageView.PushPage(searchBar.Text)))
+ {
+ foreach(CoreViewContainer item in CoreRootView.ItemsSource)
+ {
+ if(item.Name == searchBar.Text)
+ {
+ CoreRootView.SelectedItem = item;
+ break;
+ }
+ }
+ }
+ }
else
await Navigation.PushModalAsync(TestCases.GetTestCases());
})
@@ -607,10 +627,11 @@ public CoreRootPage(Page rootPage, NavigationBehavior navigationBehavior = Navig
this.SetAutomationPropertiesName("Gallery");
this.SetAutomationPropertiesHelpText("Lists all gallery pages");
+ CoreRootView = new CoreRootView();
Content = new AbsoluteLayout
{
Children = {
- { new CoreRootView (), new Rectangle(0, 0.0, 1, 0.35), AbsoluteLayoutFlags.All },
+ { CoreRootView, new Rectangle(0, 0.0, 1, 0.35), AbsoluteLayoutFlags.All },
{ stackLayout, new Rectangle(0, 0.5, 1, 0.30), AbsoluteLayoutFlags.All },
{ corePageView, new Rectangle(0, 1.0, 1.0, 0.35), AbsoluteLayoutFlags.All },
}
diff --git a/Xamarin.Forms.Core.UITests.Shared/Utilities/AppExtensions.cs b/Xamarin.Forms.Core.UITests.Shared/Utilities/AppExtensions.cs
index 19d6cc13e07..3985ddf9dee 100644
--- a/Xamarin.Forms.Core.UITests.Shared/Utilities/AppExtensions.cs
+++ b/Xamarin.Forms.Core.UITests.Shared/Utilities/AppExtensions.cs
@@ -148,6 +148,8 @@ namespace Xamarin.Forms.Core.UITests
{
internal static class AppExtensions
{
+ const string goToTestButtonQuery = "* marked:'GoToTestButton'";
+
public static AppRect ScreenBounds(this IApp app)
{
return app.Query(Queries.Root()).First().Rect;
@@ -163,14 +165,13 @@ public static void NavigateToGallery(this IApp app, string page)
NavigateToGallery(app, page, null);
}
- public static void NavigateToGallery(this IApp app, string page, string visual)
+ public static void NavigateTo(this IApp app, string text)
{
- const string goToTestButtonQuery = "* marked:'GoToTestButton'";
-
- app.WaitForElement(q => q.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to appear", TimeSpan.FromMinutes(2));
-
- var text = Regex.Match(page, "'(?[^']*)'").Groups["text"].Value;
+ NavigateTo(app, text, null);
+ }
+ public static void NavigateTo(this IApp app, string text, string visual)
+ {
app.WaitForElement("SearchBar");
app.ClearText(q => q.Raw("* marked:'SearchBar'"));
app.EnterText(q => q.Raw("* marked:'SearchBar'"), text);
@@ -187,7 +188,14 @@ public static void NavigateToGallery(this IApp app, string page, string visual)
app.Tap(q => q.Raw(goToTestButtonQuery));
}
- app.WaitForNoElement(o => o.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(2));
+ app.WaitForNoElement(o => o.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(1));
+ }
+
+ public static void NavigateToGallery(this IApp app, string page, string visual)
+ {
+ app.WaitForElement(q => q.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to appear", TimeSpan.FromMinutes(2));
+ var text = Regex.Match(page, "'(?[^']*)'").Groups["text"].Value;
+ NavigateTo(app, text, visual);
}
diff --git a/Xamarin.Forms.Core.UnitTests/GridTests.cs b/Xamarin.Forms.Core.UnitTests/GridTests.cs
index 9f77ee92d54..248a114aed5 100644
--- a/Xamarin.Forms.Core.UnitTests/GridTests.cs
+++ b/Xamarin.Forms.Core.UnitTests/GridTests.cs
@@ -106,6 +106,171 @@ public void StarRowsHaveEqualHeights()
Assert.That(column0Height, Is.LessThan(gridHeight));
}
+ [Test(Description = "Columns with a Star width less than one should not cause the Grid to contract below the target width; see https://github.com/xamarin/Xamarin.Forms/issues/11742")]
+ public void StarWidthsLessThanOneShouldNotContractGrid()
+ {
+ var grid = new Grid
+ {
+ VerticalOptions = LayoutOptions.Start,
+ ColumnSpacing = 12
+ };
+
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0.8, GridUnitType.Star) });
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
+
+ grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
+
+ var label0 = new ColumnTestLabel
+ {
+ VerticalOptions = LayoutOptions.Start,
+ LineBreakMode = LineBreakMode.WordWrap,
+ Text = "This should wrap a bit"
+ };
+
+ var label1 = new ColumnTestLabel
+ {
+ VerticalOptions = LayoutOptions.Start,
+ LineBreakMode = LineBreakMode.WordWrap,
+ Text = "This ought to fit in the space just fine."
+ };
+
+ grid.Children.Add(label0, 0, 0);
+ grid.Children.Add(label1, 1, 0);
+
+ var gridWidth = 411;
+ grid.Measure(gridWidth, 1000);
+ var column0Width = grid.ColumnDefinitions[0].ActualWidth;
+ var column1Width = grid.ColumnDefinitions[1].ActualWidth;
+
+ Assert.That(column0Width, Is.LessThan(column1Width));
+
+ // Having a first column which is a fraction of a Star width should not cause the grid
+ // to contract below the target width
+ Assert.That(column0Width + column1Width, Is.GreaterThanOrEqualTo(gridWidth));
+ }
+
+ [Test]
+ public void ContractionAppliedEquallyOnMultiStarColumns()
+ {
+ var grid = new Grid { ColumnSpacing = 0 };
+
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(2, GridUnitType.Star) });
+
+ grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
+
+ var smaller = new Size(100, 10);
+ var larger = new Size(200, 10);
+ var min = new Size(0, 10);
+
+ var label0 = new FixedSizeLabel(min, smaller)
+ {
+ Text = "label0"
+ };
+
+ var label1 = new FixedSizeLabel(min, larger)
+ {
+ Text = "label1"
+ };
+
+ grid.Children.Add(label0, 0, 0);
+ grid.Children.Add(label1, 1, 0);
+
+ // requested total width is 300, so this will force a contraction to 200
+ grid.Measure(200, 100);
+ var column0Width = grid.ColumnDefinitions[0].ActualWidth;
+ var column1Width = grid.ColumnDefinitions[1].ActualWidth;
+
+ Assert.That(column0Width, Is.EqualTo(column1Width / 2));
+ }
+
+ [Test]
+ public void AllStarColumnsCanOnlyContractToTheLargestMinimum()
+ {
+ var grid = new Grid { ColumnSpacing = 0 };
+
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
+ grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
+
+ grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
+
+ var leftColumn = new Size(100, 10);
+ var rightColumn = new Size(100, 10);
+ var largerMin = new Size(75, 10);
+ var smallerMin = new Size(50, 10);
+
+ var leftLabel = new FixedSizeLabel(largerMin, leftColumn)
+ {
+ Text = "label0"
+ };
+
+ var rightLabel = new FixedSizeLabel(smallerMin, rightColumn)
+ {
+ Text = "label1"
+ };
+
+ grid.Children.Add(leftLabel, 0, 0);
+ grid.Children.Add(rightLabel, 1, 0);
+
+ // requested total width is 200, so this will force an attemped contraction to 100
+ grid.Measure(100, 100);
+ var column0Width = grid.ColumnDefinitions[0].ActualWidth;
+ var column1Width = grid.ColumnDefinitions[1].ActualWidth;
+
+ Assert.That(column0Width, Is.EqualTo(column1Width));
+ }
+
+ [Test]
+ public void ContractionAppliedEquallyOnMultiStarRows()
+ {
+ var grid = new Grid { ColumnSpacing = 0, RowSpacing = 0 };
+
+ grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
+ grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2, GridUnitType.Star) });
+
+ var smaller = new Size(100, 100);
+ var larger = new Size(100, 200);
+ var min = new Size(100, 0);
+
+ var label0 = new FixedSizeLabel(min, smaller)
+ {
+ Text = "label0"
+ };
+
+ var label1 = new FixedSizeLabel(min, larger)
+ {
+ Text = "label1"
+ };
+
+ grid.Children.Add(label0, 0, 0);
+ grid.Children.Add(label1, 1, 0);
+
+ // requested total height is 300, so this will force a contraction to 200
+ grid.Measure(200, 200);
+ var column0Height = grid.RowDefinitions[0].ActualHeight;
+ var column1Height = grid.RowDefinitions[1].ActualHeight;
+
+ Assert.That(column0Height, Is.EqualTo(column1Height / 2));
+ }
+
+ class FixedSizeLabel : Label
+ {
+ readonly Size _minimumSize;
+ readonly Size _requestedSize;
+
+ public FixedSizeLabel(Size minimumSize, Size requestedSize)
+ {
+ IsPlatformEnabled = true;
+ _minimumSize = minimumSize;
+ _requestedSize = requestedSize;
+ }
+
+ protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
+ {
+ return new SizeRequest(_requestedSize, _minimumSize);
+ }
+ }
+
class ColumnTestLabel : Label
{
public ColumnTestLabel()
diff --git a/Xamarin.Forms.Core.UnitTests/PathSegmentTests.cs b/Xamarin.Forms.Core.UnitTests/PathSegmentTests.cs
index 23552a01b0b..e016c52bef1 100644
--- a/Xamarin.Forms.Core.UnitTests/PathSegmentTests.cs
+++ b/Xamarin.Forms.Core.UnitTests/PathSegmentTests.cs
@@ -5,12 +5,16 @@ namespace Xamarin.Forms.Core.UnitTests
{
public class PathSegmentTests : BaseTestFixture
{
+ PointCollectionConverter _pointCollectionConverter;
+
[SetUp]
public override void Setup()
{
base.Setup();
Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental });
+
+ _pointCollectionConverter = new PointCollectionConverter();
}
[Test]
@@ -54,37 +58,62 @@ public void TestLineSegmentConstructor()
Assert.AreEqual(50, lineSegment2.Point.Y);
}
- [Test]
- public void TestPolyBezierSegmentConstructor()
+ [TestCase("", 0)]
+ [TestCase("0 48", 1)]
+ [TestCase("0 48, 0 144", 2)]
+ [TestCase("0 48, 0 144, 96 150", 3)]
+ [TestCase("0 48, 0 144, 96 150, 100 0", 4)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0", 5)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96", 6)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96", 7)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192", 8)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200", 9)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200 144 48", 10)]
+ public void TestPolyBezierSegmentConstructor(string points, int count)
{
- var polyBezierSegment1 = new PolyBezierSegment();
- Assert.IsNotNull(polyBezierSegment1);
+ var pointCollection = (PointCollection)_pointCollectionConverter.ConvertFromInvariantString(points);
- var polyBezierSegment2 = new PolyBezierSegment(new PointCollection { new Point(0, 0), new Point(1, 1) });
- Assert.IsNotNull(polyBezierSegment2);
- Assert.AreEqual(2, polyBezierSegment2.Points.Count);
+ var polyBezierSegment = new PolyBezierSegment(pointCollection);
+ Assert.IsNotNull(polyBezierSegment);
+ Assert.AreEqual(count, polyBezierSegment.Points.Count);
}
- [Test]
- public void TestPolyLineSegmentConstructor()
+ [TestCase("", 0)]
+ [TestCase("0 48", 1)]
+ [TestCase("0 48, 0 144", 2)]
+ [TestCase("0 48, 0 144, 96 150", 3)]
+ [TestCase("0 48, 0 144, 96 150, 100 0", 4)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0", 5)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96", 6)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96", 7)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192", 8)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200", 9)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200 144 48", 10)]
+ public void TestPolyLineSegmentConstructor(string points, int count)
{
- var polyLineSegment1 = new PolyLineSegment();
- Assert.IsNotNull(polyLineSegment1);
-
- var polyLineSegment2 = new PolyLineSegment(new PointCollection { new Point(0, 0), new Point(1, 1) });
- Assert.IsNotNull(polyLineSegment2);
- Assert.AreEqual(2, polyLineSegment2.Points.Count);
+ var pointCollection = (PointCollection)_pointCollectionConverter.ConvertFromInvariantString(points);
+ var polyLineSegment = new PolyLineSegment(pointCollection);
+ Assert.IsNotNull(polyLineSegment);
+ Assert.AreEqual(count, polyLineSegment.Points.Count);
}
- [Test]
- public void TestPolyQuadraticBezierSegmentConstructor()
+ [TestCase("", 0)]
+ [TestCase("0 48", 1)]
+ [TestCase("0 48, 0 144", 2)]
+ [TestCase("0 48, 0 144, 96 150", 3)]
+ [TestCase("0 48, 0 144, 96 150, 100 0", 4)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0", 5)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96", 6)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96", 7)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192", 8)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200", 9)]
+ [TestCase("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200 144 48", 10)]
+ public void TestPolyQuadraticBezierSegmentConstructor(string points, int count)
{
- var polyQuadraticBezierSegment1 = new PolyQuadraticBezierSegment();
- Assert.IsNotNull(polyQuadraticBezierSegment1);
-
- var polyQuadraticBezierSegment2 = new PolyQuadraticBezierSegment(new PointCollection { new Point(0, 0), new Point(1, 1) });
- Assert.IsNotNull(polyQuadraticBezierSegment2);
- Assert.AreEqual(2, polyQuadraticBezierSegment2.Points.Count);
+ var pointCollection = (PointCollection)_pointCollectionConverter.ConvertFromInvariantString(points);
+ var polyQuadraticBezierSegment = new PolyQuadraticBezierSegment(pointCollection);
+ Assert.IsNotNull(polyQuadraticBezierSegment);
+ Assert.AreEqual(count, polyQuadraticBezierSegment.Points.Count);
}
[Test]
diff --git a/Xamarin.Forms.Core.Windows.UITests/WindowsTestBase.cs b/Xamarin.Forms.Core.Windows.UITests/WindowsTestBase.cs
index daf147b30c8..776809e504d 100644
--- a/Xamarin.Forms.Core.Windows.UITests/WindowsTestBase.cs
+++ b/Xamarin.Forms.Core.Windows.UITests/WindowsTestBase.cs
@@ -19,6 +19,8 @@ public static IApp ConfigureApp()
{
if (Session == null)
Session = CreateWindowsDriver();
+ else
+ Reset();
return new WinDriverApp(Session);
}
diff --git a/Xamarin.Forms.Core/GridCalc.cs b/Xamarin.Forms.Core/GridCalc.cs
index 3526fef5ee2..f1ef3001656 100644
--- a/Xamarin.Forms.Core/GridCalc.cs
+++ b/Xamarin.Forms.Core/GridCalc.cs
@@ -220,7 +220,7 @@ void CalculateStarCells(double width, double height, double totalStarsWidth, dou
return rowHeightSum;
}
- Size ComputeCurrentSize()
+ Size ComputeCurrentSize()
{
var columnWidthSum = ComputeColumnWidthSum();
var rowHeightSum = ComputeRowHeightSum();
@@ -318,7 +318,14 @@ void ContractStarColumnsIfNeeded(double targetWidth)
continue;
}
- starColumnWidth = column.ActualWidth;
+ if (starColumnWidth == 0)
+ {
+ starColumnWidth = column.ActualWidth;
+ }
+ else
+ {
+ starColumnWidth = Math.Min(column.ActualWidth, starColumnWidth);
+ }
if (column.MinimumWidth > starColumnMinWidth)
{
@@ -335,13 +342,10 @@ void ContractStarColumnsIfNeeded(double targetWidth)
// contract as much as we can but no more
double contractionNeeded = Math.Min(contractionSpace, Math.Max(request.Width - targetWidth, 0));
- double contractFactor = contractionNeeded / contractionSpace;
- var delta = contractFactor * starColumnWidth;
-
- if (starColumnWidth - delta <= starColumnMinWidth)
- {
- delta = starColumnWidth - starColumnMinWidth;
- }
+ double contractionFactor = contractionNeeded / contractionSpace;
+ var delta = contractionFactor >= 1
+ ? starColumnWidth - starColumnMinWidth
+ : contractionFactor * (starColumnWidth - starColumnMinWidth);
for (var index = 0; index < _columns.Count; index++)
{
@@ -351,11 +355,11 @@ void ContractStarColumnsIfNeeded(double targetWidth)
continue;
}
- column.ActualWidth -= delta;
+ column.ActualWidth -= delta * column.Width.Value;
}
}
- void ContractStarRowsIfNeeded(double targetHeight)
+ void ContractStarRowsIfNeeded(double targetHeight)
{
var request = ComputeCurrentSize();
@@ -377,7 +381,14 @@ void ContractStarRowsIfNeeded(double targetHeight)
continue;
}
- starRowHeight = row.ActualHeight;
+ if (starRowHeight == 0)
+ {
+ starRowHeight = row.ActualHeight;
+ }
+ else
+ {
+ starRowHeight = Math.Min(row.ActualHeight, starRowHeight);
+ }
if (row.MinimumHeight > starRowMinHeight)
{
@@ -394,12 +405,9 @@ void ContractStarRowsIfNeeded(double targetHeight)
double contractionNeeded = Math.Min(contractionSpace, Math.Max(request.Height - targetHeight, 0));
double contractionFactor = contractionNeeded / contractionSpace;
- var delta = contractionFactor * starRowHeight;
-
- if (starRowHeight - delta <= starRowMinHeight)
- {
- delta = starRowHeight - starRowMinHeight;
- }
+ var delta = contractionFactor >= 1
+ ? starRowHeight - starRowMinHeight
+ : contractionFactor * (starRowHeight - starRowMinHeight);
for (var index = 0; index < _rows.Count; index++)
{
@@ -409,7 +417,7 @@ void ContractStarRowsIfNeeded(double targetHeight)
continue;
}
- row.ActualHeight -= delta;
+ row.ActualHeight -= delta * row.Height.Value;
}
}
@@ -535,7 +543,7 @@ void MeasureAndContractStarredColumns(double width, double height, double totalS
void MeasureAndContractStarredRows(double width, double height, double totalStarsHeight)
{
double starRowHeight;
- starRowHeight = MeasureStarredRows();
+ starRowHeight = MeasureStarredRows(width, height);
if (!double.IsPositiveInfinity(height) && double.IsPositiveInfinity(width))
{
@@ -558,6 +566,52 @@ void MeasureAndContractStarredRows(double width, double height, double totalStar
ContractStarRowsIfNeeded(height);
}
+
+ void MeasureGrid(double width, double height, bool requestSize = false)
+ {
+ EnsureRowsColumnsInitialized();
+
+ AssignAbsoluteCells();
+
+ CalculateAutoCells(width, height);
+
+ if (!requestSize)
+ {
+ ContractAutoColumnsIfNeeded(width);
+ ContractAutoRowsIfNeeded(height);
+ }
+
+ double totalStarsHeight = 0;
+ for (var index = 0; index < _rows.Count; index++)
+ {
+ RowDefinition row = _rows[index];
+ if (row.Height.IsStar)
+ totalStarsHeight += row.Height.Value;
+ }
+
+ double totalStarsWidth = 0;
+ for (var index = 0; index < _columns.Count; index++)
+ {
+ ColumnDefinition col = _columns[index];
+ if (col.Width.IsStar)
+ totalStarsWidth += col.Width.Value;
+ }
+
+ if (requestSize)
+ {
+ MeasureAndContractStarredColumns(width, height, totalStarsWidth);
+ MeasureAndContractStarredRows(width, height, totalStarsHeight);
+ }
+ else
+ {
+ CalculateStarCells(width, height, totalStarsWidth, totalStarsHeight);
+ }
+
+ ZeroUnassignedCells();
+
+ ExpandLastAutoRowIfNeeded(height, requestSize);
+ ExpandLastAutoColumnIfNeeded(width, requestSize);
+ }
double MeasuredStarredColumns(double widthConstraint, double heightConstraint)
{
@@ -583,8 +637,6 @@ void MeasureAndContractStarredRows(double width, double height, double totalStar
continue;
double assignedWidth = GetAssignedColumnWidth(child);
- // Can we start with a more reasonable constraint here? if our starred column count is greater than 1, widthConstraint _has_ to be too big
-
SizeRequest sizeRequest = child.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins);
actualWidth = Math.Max(actualWidth, sizeRequest.Request.Width - assignedWidth - (GetColumnSpan(child) - 1) * ColumnSpacing);
minimumWidth = Math.Max(minimumWidth, sizeRequest.Minimum.Width - assignedWidth - (GetColumnSpan(child) - 1) * ColumnSpacing);
@@ -598,7 +650,6 @@ void MeasureAndContractStarredRows(double width, double height, double totalStar
}
}
- //Measure the stars
starColWidth = 1;
for (var index = 0; index < _columns.Count; index++)
{
@@ -611,53 +662,7 @@ void MeasureAndContractStarredRows(double width, double height, double totalStar
return starColWidth;
}
- void MeasureGrid(double width, double height, bool requestSize = false)
- {
- EnsureRowsColumnsInitialized();
-
- AssignAbsoluteCells();
-
- CalculateAutoCells(width, height);
-
- if (!requestSize)
- {
- ContractAutoColumnsIfNeeded(width);
- ContractAutoRowsIfNeeded(height);
- }
-
- double totalStarsHeight = 0;
- for (var index = 0; index < _rows.Count; index++)
- {
- RowDefinition row = _rows[index];
- if (row.Height.IsStar)
- totalStarsHeight += row.Height.Value;
- }
-
- double totalStarsWidth = 0;
- for (var index = 0; index < _columns.Count; index++)
- {
- ColumnDefinition col = _columns[index];
- if (col.Width.IsStar)
- totalStarsWidth += col.Width.Value;
- }
-
- if (requestSize)
- {
- MeasureAndContractStarredColumns(width, height, totalStarsWidth);
- MeasureAndContractStarredRows(width, height, totalStarsHeight);
- }
- else
- {
- CalculateStarCells(width, height, totalStarsWidth, totalStarsHeight);
- }
-
- ZeroUnassignedCells();
-
- ExpandLastAutoRowIfNeeded(height, requestSize);
- ExpandLastAutoColumnIfNeeded(width, requestSize);
- }
-
- double MeasureStarredRows()
+ double MeasureStarredRows(double widthConstraint, double heightConstraint)
{
double starRowHeight;
for (var iteration = 0; iteration < 2; iteration++)
@@ -680,11 +685,10 @@ void MeasureGrid(double width, double height, bool requestSize = false)
if (!child.IsVisible || GetRowSpan(child) != rowspan || !IsInRow(child, i) || NumberOfUnsetRowHeight(child) > 1)
continue;
double assignedHeight = GetAssignedRowHeight(child);
- double assignedWidth = GetAssignedColumnWidth(child);
- SizeRequest sizeRequest = child.Measure(assignedWidth, double.PositiveInfinity, MeasureFlags.IncludeMargins);
- actualHeight = Math.Max(actualHeight, sizeRequest.Request.Height - assignedHeight - RowSpacing * (GetRowSpan(child) - 1));
- minimumHeight = Math.Max(minimumHeight, sizeRequest.Minimum.Height - assignedHeight - RowSpacing * (GetRowSpan(child) - 1));
+ SizeRequest sizeRequest = child.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins);
+ actualHeight = Math.Max(actualHeight, sizeRequest.Request.Height - assignedHeight - (GetRowSpan(child) - 1) * RowSpacing);
+ minimumHeight = Math.Max(minimumHeight, sizeRequest.Minimum.Height - assignedHeight - (GetRowSpan(child) - 1) * RowSpacing);
}
if (actualHeight >= 0)
row.ActualHeight = actualHeight;
@@ -695,9 +699,6 @@ void MeasureGrid(double width, double height, bool requestSize = false)
}
}
- // 3. Star columns:
-
- //Measure the stars
starRowHeight = 1;
for (var index = 0; index < _rows.Count; index++)
{
diff --git a/Xamarin.Forms.Platform.Android/Extensions/GeometryExtensions.cs b/Xamarin.Forms.Platform.Android/Extensions/GeometryExtensions.cs
index a2a57a60813..31fa573af3b 100644
--- a/Xamarin.Forms.Platform.Android/Extensions/GeometryExtensions.cs
+++ b/Xamarin.Forms.Platform.Android/Extensions/GeometryExtensions.cs
@@ -119,12 +119,15 @@ public static APath ToAPath(this Geometry geometry, Context context)
PolyBezierSegment polyBezierSegment = pathSegment as PolyBezierSegment;
PointCollection points = polyBezierSegment.Points;
- for (int i = 0; i < points.Count; i += 3)
+ if (points.Count >= 3)
{
- path.CubicTo(
- density * (float)points[i + 0].X, density * (float)points[i + 0].Y,
- density * (float)points[i + 1].X, density * (float)points[i + 1].Y,
- density * (float)points[i + 2].X, density * (float)points[i + 2].Y);
+ for (int i = 0; i < points.Count; i += 3)
+ {
+ path.CubicTo(
+ density * (float)points[i + 0].X, density * (float)points[i + 0].Y,
+ density * (float)points[i + 1].X, density * (float)points[i + 1].Y,
+ density * (float)points[i + 2].X, density * (float)points[i + 2].Y);
+ }
}
lastPoint = points[points.Count - 1];
@@ -146,11 +149,14 @@ public static APath ToAPath(this Geometry geometry, Context context)
PolyQuadraticBezierSegment polyBezierSegment = pathSegment as PolyQuadraticBezierSegment;
PointCollection points = polyBezierSegment.Points;
- for (int i = 0; i < points.Count; i += 2)
+ if (points.Count >= 2)
{
- path.QuadTo(
- density * (float)points[i + 0].X, density * (float)points[i + 0].Y,
- density * (float)points[i + 1].X, density * (float)points[i + 1].Y);
+ for (int i = 0; i < points.Count; i += 2)
+ {
+ path.QuadTo(
+ density * (float)points[i + 0].X, density * (float)points[i + 0].Y,
+ density * (float)points[i + 1].X, density * (float)points[i + 1].Y);
+ }
}
lastPoint = points[points.Count - 1];
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
index af41e2ad77c..188f2d78b95 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
@@ -158,7 +158,7 @@ protected virtual BottomSheetDialog CreateMoreBottomSheet(Action
{
- selectCallback(ShellItem.Items[index], dialog);
+ selectCallback(ShellItemController.GetItems()[index], dialog);
});
}
@@ -175,7 +175,7 @@ protected virtual BottomSheetDialog CreateMoreBottomSheet(Action CreateTabList(ShellItem shellItem)
{
var items = new List<(string title, ImageSource icon, bool tabEnabled)>();
+ var shellItems = ((IShellItemController)shellItem).GetItems();
- for (int i = 0; i < shellItem.Items.Count; i++)
+ for (int i = 0; i < shellItems.Count; i++)
{
- var item = shellItem.Items[i];
+ var item = shellItems[i];
items.Add((item.Title, item.Icon, item.IsEnabled));
}
return items;
diff --git a/Xamarin.Forms.Platform.Tizen/FormsApplication.cs b/Xamarin.Forms.Platform.Tizen/FormsApplication.cs
index 618c88e8e8f..24d17989a1d 100644
--- a/Xamarin.Forms.Platform.Tizen/FormsApplication.cs
+++ b/Xamarin.Forms.Platform.Tizen/FormsApplication.cs
@@ -19,13 +19,11 @@ public class FormsApplication : CoreUIApplication
{
ITizenPlatform _platform;
Application _application;
- bool _isInitialStart;
Window _window;
bool _useBezelInteration;
protected FormsApplication()
{
- _isInitialStart = true;
}
///
@@ -93,17 +91,6 @@ protected override void OnTerminate()
}
}
- protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
- {
- base.OnAppControlReceived(e);
-
- if (!_isInitialStart && _application != null)
- {
- _application.SendResume();
- }
- _isInitialStart = false;
- }
-
protected override void OnPause()
{
base.OnPause();
diff --git a/Xamarin.Forms.Platform.Tizen/PopupManager.cs b/Xamarin.Forms.Platform.Tizen/PopupManager.cs
index 5f489ed0630..c49be820ade 100644
--- a/Xamarin.Forms.Platform.Tizen/PopupManager.cs
+++ b/Xamarin.Forms.Platform.Tizen/PopupManager.cs
@@ -57,19 +57,15 @@ void OnBusySetRequest(Page sender, bool enabled)
if (Device.Idiom == TargetIdiom.Phone)
{
- _pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
- _pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
+ _pageBusyDialog.SetTitleBackgroundColor(EColor.Transparent);
+ _pageBusyDialog.SetContentBackgroundColor(EColor.Transparent);
}
else if (Device.Idiom == TargetIdiom.Watch)
{
- _pageBusyDialog.Style = "circle";
+ _pageBusyDialog.SetWatchCircleStyle();
}
- var activity = new EProgressBar(_pageBusyDialog)
- {
- Style = "process_large",
- IsPulseMode = true,
- };
+ var activity = new EProgressBar(_pageBusyDialog) { IsPulseMode = true }.SetLargeStyle();
activity.PlayPulse();
activity.Show();
@@ -97,7 +93,7 @@ void OnAlertRequest(Page sender, AlertArguments arguments)
var alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null));
alert.Title = arguments.Title;
- var message = arguments.Message.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(Environment.NewLine, "
");
+ var message = arguments.Message?.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(Environment.NewLine, "
");
alert.Message = message;
var cancel = new EButton(alert) { Text = arguments.Cancel };
diff --git a/Xamarin.Forms.Platform.Tizen/Shell/ShellSectionNavigation.cs b/Xamarin.Forms.Platform.Tizen/Shell/ShellSectionNavigation.cs
index b30aad2fb7e..e30478dcd57 100644
--- a/Xamarin.Forms.Platform.Tizen/Shell/ShellSectionNavigation.cs
+++ b/Xamarin.Forms.Platform.Tizen/Shell/ShellSectionNavigation.cs
@@ -179,10 +179,13 @@ void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e)
EvasObject GetOrCreatePage(Page page)
{
- Native.Page native = Platform.GetOrCreateRenderer(page).NativeView as Native.Page;
+ var native = Platform.GetOrCreateRenderer(page).NativeView;
_pageToNative[page] = native;
_nativeToPage[native] = page;
- native.BackgroundColor = (page.BackgroundColor != Xamarin.Forms.Color.Default ? page.BackgroundColor.ToNative() : ElmSharp.Color.White);
+ if(native is Native.Page np)
+ {
+ np.BackgroundColor = (page.BackgroundColor != Xamarin.Forms.Color.Default ? page.BackgroundColor.ToNative() : ElmSharp.Color.White);
+ }
PackEnd(native);
return native;
}
diff --git a/Xamarin.Forms.Platform.Tizen/ThemeConstants.cs b/Xamarin.Forms.Platform.Tizen/ThemeConstants.cs
index 9f0fa06061f..71a1450e445 100644
--- a/Xamarin.Forms.Platform.Tizen/ThemeConstants.cs
+++ b/Xamarin.Forms.Platform.Tizen/ThemeConstants.cs
@@ -214,6 +214,8 @@ public class Watch
public class ColorClass
{
public const string Title = "text_maintitle";
+ public const string TitleBackground = "bg_title";
+ public const string ContentBackground = "bg_content";
public class TV
{
diff --git a/Xamarin.Forms.Platform.Tizen/ThemeManager.cs b/Xamarin.Forms.Platform.Tizen/ThemeManager.cs
index fd1b515b884..62204d09e47 100644
--- a/Xamarin.Forms.Platform.Tizen/ThemeManager.cs
+++ b/Xamarin.Forms.Platform.Tizen/ThemeManager.cs
@@ -291,6 +291,16 @@ public static void SetTitleColor(this Popup popup, EColor color)
popup.SetPartColor(Device.Idiom == TargetIdiom.TV ? ThemeConstants.Popup.ColorClass.TV.Title : ThemeConstants.Popup.ColorClass.Title, color);
}
+ public static void SetTitleBackgroundColor(this Popup popup, EColor color)
+ {
+ popup.SetPartColor(ThemeConstants.Popup.ColorClass.TitleBackground, color);
+ }
+
+ public static void SetContentBackgroundColor(this Popup popup, EColor color)
+ {
+ popup.SetPartColor(ThemeConstants.Popup.ColorClass.ContentBackground, color);
+ }
+
public static bool SetTitleTextPart(this Popup popup, string title)
{
return popup.SetPartText(ThemeConstants.Popup.Parts.Title, title);
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml b/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml
new file mode 100644
index 00000000000..e2185370f3d
--- /dev/null
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml.cs b/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml.cs
new file mode 100644
index 00000000000..cb3c7f853ee
--- /dev/null
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellPageWrapper.xaml.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.UI.Xaml;
+
+namespace Xamarin.Forms.Platform.UWP
+{
+ partial class ShellPageWrapper
+ {
+ public ShellPageWrapper()
+ {
+ InitializeComponent();
+ }
+
+ public Page Page { get; set; }
+ protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+ LoadPage();
+ }
+
+ protected override void OnNavigatedFrom(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
+ {
+ base.OnNavigatedFrom(e);
+ Root.Content = null;
+ }
+
+ public void LoadPage()
+ {
+ if (Page != null)
+ {
+ var container = Page.GetOrCreateRenderer().ContainerElement;
+ Root.Content = container;
+ container.Loaded -= OnPageLoaded;
+ container.Loaded += OnPageLoaded;
+ }
+ }
+
+ private void OnPageLoaded(object sender, RoutedEventArgs e)
+ {
+ var frameworkElement = sender as FrameworkElement;
+ Page.Layout(new Rectangle(0, 0, frameworkElement.ActualWidth, frameworkElement.ActualHeight));
+ }
+ }
+}
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellSectionRenderer.cs b/Xamarin.Forms.Platform.UAP/Shell/ShellSectionRenderer.cs
index 235d49a6169..b9c084509c4 100644
--- a/Xamarin.Forms.Platform.UAP/Shell/ShellSectionRenderer.cs
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellSectionRenderer.cs
@@ -162,43 +162,6 @@ internal void NavigateToContent(ShellNavigationSource source, ShellContent shell
}
}
- internal class ShellPageWrapper : Windows.UI.Xaml.Controls.Page
- {
- public ShellPageWrapper()
- {
- }
-
- public Page Page { get; set; }
- protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
- {
- base.OnNavigatedTo(e);
- LoadPage();
- }
-
- protected override void OnNavigatedFrom(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
- {
- base.OnNavigatedFrom(e);
- Content = null;
- }
-
- public void LoadPage()
- {
- if (Page != null)
- {
- var container = Page.GetOrCreateRenderer().ContainerElement;
- Content = container;
- container.Loaded -= OnPageLoaded;
- container.Loaded += OnPageLoaded;
- }
- }
-
- private void OnPageLoaded(object sender, RoutedEventArgs e)
- {
- var frameworkElement = sender as FrameworkElement;
- Page.Layout(new Rectangle(0, 0, frameworkElement.ActualWidth, frameworkElement.ActualHeight));
- }
- }
-
NavigationTransitionInfo GetTransitionInfo(ShellNavigationSource navSource)
{
switch (navSource)
diff --git a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj
index 657e6196e40..0f88c133788 100644
--- a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj
+++ b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj
@@ -31,6 +31,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/Xamarin.Forms.Platform.iOS/EventTracker.cs b/Xamarin.Forms.Platform.iOS/EventTracker.cs
index c8962b87a9f..07142af16da 100644
--- a/Xamarin.Forms.Platform.iOS/EventTracker.cs
+++ b/Xamarin.Forms.Platform.iOS/EventTracker.cs
@@ -59,6 +59,12 @@ ObservableCollection ElementGestureRecognizers
}
}
+ internal void Disconnect()
+ {
+ if (ElementGestureRecognizers != null)
+ ElementGestureRecognizers.CollectionChanged -= _collectionChangedHandler;
+ }
+
public void Dispose()
{
if (_disposed)
@@ -77,8 +83,7 @@ public void Dispose()
_gestureRecognizers.Clear();
- if (ElementGestureRecognizers != null)
- ElementGestureRecognizers.CollectionChanged -= _collectionChangedHandler;
+ Disconnect();
_handler = null;
}
diff --git a/Xamarin.Forms.Platform.iOS/Extensions/GeometryExtensions.cs b/Xamarin.Forms.Platform.iOS/Extensions/GeometryExtensions.cs
index 99a0d55ee95..cba117e523d 100644
--- a/Xamarin.Forms.Platform.iOS/Extensions/GeometryExtensions.cs
+++ b/Xamarin.Forms.Platform.iOS/Extensions/GeometryExtensions.cs
@@ -112,14 +112,18 @@ public static PathData ToCGPath(this Geometry geometry, Transform renderTransfor
PolyBezierSegment polyBezierSegment = pathSegment as PolyBezierSegment;
PointCollection points = polyBezierSegment.Points;
- for (int i = 0; i < points.Count; i += 3)
+ if (points.Count >= 3)
{
- pathData.Data.AddCurveToPoint(
- transform,
- points[i].ToPointF(),
- points[i + 1].ToPointF(),
- points[i + 2].ToPointF());
+ for (int i = 0; i < points.Count; i += 3)
+ {
+ pathData.Data.AddCurveToPoint(
+ transform,
+ points[i].ToPointF(),
+ points[i + 1].ToPointF(),
+ points[i + 2].ToPointF());
+ }
}
+
lastPoint = points[points.Count - 1];
}
@@ -143,14 +147,17 @@ public static PathData ToCGPath(this Geometry geometry, Transform renderTransfor
PolyQuadraticBezierSegment polyBezierSegment = pathSegment as PolyQuadraticBezierSegment;
PointCollection points = polyBezierSegment.Points;
- for (int i = 0; i < points.Count; i += 2)
+ if (points.Count >= 2)
{
- pathData.Data.AddQuadCurveToPoint(
- transform,
- new nfloat(points[i + 0].X),
- new nfloat(points[i + 0].Y),
- new nfloat(points[i + 1].X),
- new nfloat(points[i + 1].Y));
+ for (int i = 0; i < points.Count; i += 2)
+ {
+ pathData.Data.AddQuadCurveToPoint(
+ transform,
+ new nfloat(points[i + 0].X),
+ new nfloat(points[i + 0].Y),
+ new nfloat(points[i + 1].X),
+ new nfloat(points[i + 1].Y));
+ }
}
lastPoint = points[points.Count - 1];
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/EditorRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/EditorRenderer.cs
index 667b615acd1..5444c7f9138 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/EditorRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/EditorRenderer.cs
@@ -116,7 +116,7 @@ void CreatePlaceholderLabel()
new NSObject[] { _placeholderLabel }, new NSObject[] { new NSString("_placeholderLabel") })
);
- _placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = true;
+ _placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
_placeholderLabel.AttributedText = _placeholderLabel.AttributedText.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
Control.AddConstraints(hConstraints);
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/IDisconnectable.cs b/Xamarin.Forms.Platform.iOS/Renderers/IDisconnectable.cs
new file mode 100644
index 00000000000..f8efba167a0
--- /dev/null
+++ b/Xamarin.Forms.Platform.iOS/Renderers/IDisconnectable.cs
@@ -0,0 +1,8 @@
+using System;
+namespace Xamarin.Forms.Platform.iOS
+{
+ internal interface IDisconnectable
+ {
+ void Disconnect();
+ }
+}
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/PageRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/PageRenderer.cs
index ea604ebd215..2b00312f48c 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/PageRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/PageRenderer.cs
@@ -9,7 +9,7 @@
namespace Xamarin.Forms.Platform.iOS
{
- public class PageRenderer : UIViewController, IVisualElementRenderer, IEffectControlProvider, IAccessibilityElementsController, IShellContentInsetObserver
+ public class PageRenderer : UIViewController, IVisualElementRenderer, IEffectControlProvider, IAccessibilityElementsController, IShellContentInsetObserver, IDisconnectable
{
bool _disposed;
EventTracker _events;
@@ -102,7 +102,7 @@ public UIView NativeView
{
get { return _disposed ? null : View; }
}
-
+
public void SetElement(VisualElement element)
{
VisualElement oldElement = Element;
@@ -166,7 +166,7 @@ public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
- if (_disposed)
+ if (_disposed || Element == null)
return;
if (Element.Parent is BaseShellItem)
@@ -189,7 +189,7 @@ public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
- if (_disposed)
+ if (_disposed || Element == null)
return;
UpdateStatusBarPrefersHidden();
@@ -207,7 +207,7 @@ public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
- if (_disposed)
+ if (_disposed || Element == null)
return;
if (Element.Parent is CarouselPage)
@@ -252,6 +252,25 @@ public override void ViewWillDisappear(bool animated)
NativeView?.Window?.EndEditing(true);
}
+ void IDisconnectable.Disconnect()
+ {
+ if (_shellSection != null)
+ {
+ ((IShellSectionController)_shellSection).RemoveContentInsetObserver(this);
+ _shellSection = null;
+ }
+
+ if (Element != null)
+ {
+ Element.PropertyChanged -= OnHandlePropertyChanged;
+ Platform.SetRenderer(Element, null);
+ Element = null;
+ }
+
+ _events?.Disconnect();
+ _packager?.Disconnect();
+ _tracker?.Disconnect();
+ }
protected override void Dispose(bool disposing)
{
@@ -260,36 +279,18 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- if (_shellSection != null)
- {
- ((IShellSectionController)_shellSection).RemoveContentInsetObserver(this);
- _shellSection = null;
- }
-
- Element.PropertyChanged -= OnHandlePropertyChanged;
- Platform.SetRenderer(Element, null);
+ var page = Page;
+ (this as IDisconnectable).Disconnect();
_pageLifecycleManager?.Dispose();
+ _events?.Dispose();
+ _packager?.Dispose();
+ _tracker?.Dispose();
+ _events = null;
+ _packager = null;
+ _tracker = null;
_pageLifecycleManager = null;
- if (_events != null)
- {
- _events.Dispose();
- _events = null;
- }
-
- if (_packager != null)
- {
- _packager.Dispose();
- _packager = null;
- }
-
- if (_tracker != null)
- {
- _tracker.Dispose();
- _tracker = null;
- }
-
Element = null;
Container?.Dispose();
_pageContainer = null;
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/SearchBarRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/SearchBarRenderer.cs
index 5e8a1b6c7b7..8d40d240729 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/SearchBarRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/SearchBarRenderer.cs
@@ -215,8 +215,8 @@ void OnEditingStarted(object sender, EventArgs e)
void OnSearchButtonClicked(object sender, EventArgs e)
{
- Element.OnSearchButtonPressed();
- Control.ResignFirstResponder();
+ Element?.OnSearchButtonPressed();
+ Control?.ResignFirstResponder();
}
void OnTextChanged(object sender, UISearchBarTextChangedEventArgs a)
@@ -433,4 +433,4 @@ void UpdateSearchBarStyle()
Control.SearchBarStyle = Element.OnThisPlatform().GetSearchBarStyle().ToNativeSearchBarStyle();
}
}
-}
\ No newline at end of file
+}
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellItemRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellItemRenderer.cs
index 516be0f3d4c..6743d5fd85c 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellItemRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellItemRenderer.cs
@@ -10,7 +10,7 @@
namespace Xamarin.Forms.Platform.iOS
{
- public class ShellItemRenderer : UITabBarController, IShellItemRenderer, IAppearanceObserver, IUINavigationControllerDelegate
+ public class ShellItemRenderer : UITabBarController, IShellItemRenderer, IAppearanceObserver, IUINavigationControllerDelegate, IDisconnectable
{
#region IShellItemRenderer
@@ -113,36 +113,60 @@ public override void ViewDidLoad()
};
}
- protected override void Dispose(bool disposing)
+ void IDisconnectable.Disconnect()
{
- base.Dispose(disposing);
-
- if (disposing && !_disposed)
+ if (_sectionRenderers != null)
{
- _disposed = true;
foreach (var kvp in _sectionRenderers.ToList())
{
- var renderer = kvp.Value;
- RemoveRenderer(renderer);
+ var renderer = kvp.Value as IDisconnectable;
+ renderer?.Disconnect();
+ kvp.Value.ShellSection.PropertyChanged -= OnShellSectionPropertyChanged;
}
+ }
- if (_displayedPage != null)
- _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged;
+ if (_displayedPage != null)
+ _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged;
- if (_currentSection != null)
- ((IShellSectionController)_currentSection).RemoveDisplayedPageObserver(this);
+ if (_currentSection != null)
+ ((IShellSectionController)_currentSection).RemoveDisplayedPageObserver(this);
- _sectionRenderers.Clear();
+ if(ShellItem != null)
ShellItem.PropertyChanged -= OnElementPropertyChanged;
- ((IShellController)_context.Shell).RemoveAppearanceObserver(this);
+
+ if(_context?.Shell is IShellController shellController)
+ shellController.RemoveAppearanceObserver(this);
+
+ if(ShellItemController != null)
ShellItemController.ItemsCollectionChanged -= OnItemsCollectionChanged;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+ if (disposing)
+ {
+ (this as IDisconnectable).Disconnect();
+
+ foreach (var kvp in _sectionRenderers.ToList())
+ {
+ var renderer = kvp.Value;
+ RemoveRenderer(renderer);
+ }
+
+ _sectionRenderers.Clear();
CurrentRenderer = null;
_shellItem = null;
_currentSection = null;
_displayedPage = null;
}
+
+ base.Dispose(disposing);
}
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellItemTransition.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellItemTransition.cs
index e21a3bf44ce..c17cf83732a 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellItemTransition.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellItemTransition.cs
@@ -10,6 +10,7 @@ public Task Transition(IShellItemRenderer oldRenderer, IShellItemRenderer newRen
TaskCompletionSource task = new TaskCompletionSource();
var oldView = oldRenderer.ViewController.View;
var newView = newRenderer.ViewController.View;
+ oldView.Layer.RemoveAllAnimations();
newView.Alpha = 0;
newView.Superview.InsertSubviewAbove(newView, oldView);
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellRenderer.cs
index 374c8be8841..f54b7ff6cfb 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellRenderer.cs
@@ -249,6 +249,7 @@ protected virtual void OnElementSet(Shell element)
protected async void SetCurrentShellItemController(IShellItemRenderer value)
{
var oldRenderer = _currentShellItemRenderer;
+ (oldRenderer as IDisconnectable)?.Disconnect();
var newRenderer = value;
_currentShellItemRenderer = value;
@@ -258,7 +259,7 @@ protected async void SetCurrentShellItemController(IShellItemRenderer value)
View.SendSubviewToBack(newRenderer.ViewController.View);
newRenderer.ViewController.View.Frame = View.Bounds;
-
+
if (oldRenderer != null)
{
var transition = CreateShellItemTransition();
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRenderer.cs
index 2202f322ff8..15857b00d1b 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRenderer.cs
@@ -11,7 +11,7 @@
namespace Xamarin.Forms.Platform.iOS
{
- public class ShellSectionRenderer : UINavigationController, IShellSectionRenderer, IAppearanceObserver
+ public class ShellSectionRenderer : UINavigationController, IShellSectionRenderer, IAppearanceObserver, IDisconnectable
{
#region IShellContentRenderer
@@ -171,6 +171,31 @@ public override void ViewDidLoad()
UpdateFlowDirection();
}
+
+
+ void IDisconnectable.Disconnect()
+ {
+ (_renderer as IDisconnectable)?.Disconnect();
+
+ if (_displayedPage != null)
+ _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged;
+
+ if (_shellSection != null)
+ {
+ _shellSection.PropertyChanged -= HandlePropertyChanged;
+ ((IShellSectionController)ShellSection).NavigationRequested -= OnNavigationRequested;
+ ((IShellSectionController)ShellSection).RemoveDisplayedPageObserver(this);
+ }
+
+
+ if (_context.Shell != null)
+ {
+ _context.Shell.PropertyChanged -= HandleShellPropertyChanged;
+ ((IShellController)_context.Shell).RemoveAppearanceObserver(this);
+ }
+
+ }
+
protected override void Dispose(bool disposing)
{
if (_disposed)
@@ -182,15 +207,7 @@ protected override void Dispose(bool disposing)
_disposed = true;
_renderer.Dispose();
_appearanceTracker.Dispose();
- _shellSection.PropertyChanged -= HandlePropertyChanged;
- _context.Shell.PropertyChanged -= HandleShellPropertyChanged;
-
- if (_displayedPage != null)
- _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged;
-
- ((IShellSectionController)_shellSection).NavigationRequested -= OnNavigationRequested;
- ((IShellController)_context.Shell).RemoveAppearanceObserver(this);
- ((IShellSectionController)ShellSection).RemoveDisplayedPageObserver(this);
+ (this as IDisconnectable).Disconnect();
foreach (var tracker in ShellSection.Stack)
{
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRootRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRootRenderer.cs
index 2b7d31cc584..f4f63e37ed2 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRootRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRootRenderer.cs
@@ -7,7 +7,7 @@
namespace Xamarin.Forms.Platform.iOS
{
- public class ShellSectionRootRenderer : UIViewController, IShellSectionRootRenderer
+ public class ShellSectionRootRenderer : UIViewController, IShellSectionRootRenderer, IDisconnectable
{
#region IShellSectionRootRenderer
@@ -117,17 +117,39 @@ public override void ViewSafeAreaInsetsDidChange()
LayoutHeader();
}
+
+
+ void IDisconnectable.Disconnect()
+ {
+ if (ShellSection != null)
+ ShellSection.PropertyChanged -= OnShellSectionPropertyChanged;
+
+ if (ShellSectionController != null)
+ ShellSectionController.ItemsCollectionChanged -= OnShellSectionItemsChanged;
+
+ if (_shellContext?.Shell != null)
+ _shellContext.Shell.PropertyChanged -= HandleShellPropertyChanged;
+
+ if (_renderers != null)
+ {
+ foreach (var renderer in _renderers)
+ {
+ var oldRenderer = renderer.Value;
+ var element = oldRenderer.Element;
+ element?.ClearValue(Platform.RendererProperty);
+ (renderer.Value as IDisconnectable)?.Disconnect();
+ }
+ }
+ }
+
protected override void Dispose(bool disposing)
{
if (_isDisposed)
return;
-
if (disposing && ShellSection != null)
{
- ShellSection.PropertyChanged -= OnShellSectionPropertyChanged;
- ShellSectionController.ItemsCollectionChanged -= OnShellSectionItemsChanged;
-
+ (this as IDisconnectable).Disconnect();
this.RemoveFromParentViewController();
@@ -145,8 +167,8 @@ protected override void Dispose(bool disposing)
oldRenderer.ViewController.RemoveFromParentViewController();
var element = oldRenderer.Element;
- oldRenderer.Dispose();
element?.ClearValue(Platform.RendererProperty);
+ oldRenderer?.Dispose();
}
_renderers.Clear();
@@ -213,8 +235,8 @@ protected virtual void LoadRenderers()
contentItems = ShellSectionController.GetItems();
}
- var renderer = Platform.CreateRenderer(page);
- Platform.SetRenderer(page, renderer);
+ var renderer = SetPageRenderer(page, item);
+
AddChildViewController(renderer.ViewController);
if (item == currentItem)
@@ -223,8 +245,6 @@ protected virtual void LoadRenderers()
_currentContent = currentItem;
_currentIndex = i;
}
-
- _renderers[item] = renderer;
}
}
@@ -402,15 +422,26 @@ void OnShellSectionItemsChanged(object sender, NotifyCollectionChangedEventArgs
continue;
var page = ((IShellContentController)newItem).GetOrCreateContent();
- var renderer = Platform.CreateRenderer(page);
- Platform.SetRenderer(page, renderer);
+ var renderer = SetPageRenderer(page, newItem);
AddChildViewController(renderer.ViewController);
- _renderers[newItem] = renderer;
}
}
}
+ IVisualElementRenderer SetPageRenderer(Page page, ShellContent shellContent)
+ {
+ var oldRenderer = Platform.GetRenderer(page);
+ if(oldRenderer != null)
+ oldRenderer?.Dispose();
+
+ var renderer = Platform.CreateRenderer(page);
+ Platform.SetRenderer(page, renderer);
+ _renderers[shellContent] = renderer;
+
+ return renderer;
+ }
+
void LayoutHeader()
{
if (ShellSection == null)
diff --git a/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs
index 48bd0f45893..979e9f4f15c 100644
--- a/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs
@@ -290,8 +290,8 @@ public void UpdateFillMode(bool fillMode)
public SizeRequest GetDesiredSize()
{
return new SizeRequest(new Size(
- Math.Max(0, _pathStrokeBounds.Right),
- Math.Max(0, _pathStrokeBounds.Bottom)));
+ Math.Max(0, nfloat.IsNaN(_pathStrokeBounds.Right) ? 0 : _pathStrokeBounds.Right),
+ Math.Max(0, nfloat.IsNaN(_pathStrokeBounds.Bottom) ? 0 : _pathStrokeBounds.Bottom)));
}
public void UpdateSize(CGSize size)
diff --git a/Xamarin.Forms.Platform.iOS/VisualElementPackager.cs b/Xamarin.Forms.Platform.iOS/VisualElementPackager.cs
index 51987c260f9..8593fc0e827 100644
--- a/Xamarin.Forms.Platform.iOS/VisualElementPackager.cs
+++ b/Xamarin.Forms.Platform.iOS/VisualElementPackager.cs
@@ -49,6 +49,21 @@ public void Load()
OnChildAdded(child);
}
}
+
+ internal void Disconnect()
+ {
+ Disconnect(_element);
+ }
+
+ void Disconnect(VisualElement oldElement)
+ {
+ if (oldElement == null)
+ return;
+
+ oldElement.ChildAdded -= OnChildAdded;
+ oldElement.ChildRemoved -= OnChildRemoved;
+ oldElement.ChildrenReordered -= UpdateChildrenOrder;
+ }
protected virtual void Dispose(bool disposing)
{
@@ -182,9 +197,7 @@ void SetElement(VisualElement oldElement, VisualElement newElement)
if (oldElement != null)
{
- oldElement.ChildAdded -= OnChildAdded;
- oldElement.ChildRemoved -= OnChildRemoved;
- oldElement.ChildrenReordered -= UpdateChildrenOrder;
+ Disconnect(oldElement);
if (newElement != null)
{
diff --git a/Xamarin.Forms.Platform.iOS/VisualElementTracker.cs b/Xamarin.Forms.Platform.iOS/VisualElementTracker.cs
index 33663d96af9..0a59cb65921 100644
--- a/Xamarin.Forms.Platform.iOS/VisualElementTracker.cs
+++ b/Xamarin.Forms.Platform.iOS/VisualElementTracker.cs
@@ -65,6 +65,21 @@ public void Dispose()
public event EventHandler NativeControlUpdated;
+ internal void Disconnect()
+ {
+ Disconnect(_element);
+ }
+
+ void Disconnect(VisualElement oldElement)
+ {
+ if (oldElement == null)
+ return;
+
+ oldElement.PropertyChanged -= _propertyChangedHandler;
+ oldElement.SizeChanged -= _sizeChangedEventHandler;
+ oldElement.BatchCommitted -= _batchCommittedHandler;
+ }
+
protected virtual void Dispose(bool disposing)
{
if (_disposed)
@@ -344,9 +359,7 @@ void SetElement(VisualElement oldElement, VisualElement newElement)
{
if (oldElement != null)
{
- oldElement.PropertyChanged -= _propertyChangedHandler;
- oldElement.SizeChanged -= _sizeChangedEventHandler;
- oldElement.BatchCommitted -= _batchCommittedHandler;
+ Disconnect(oldElement);
}
_element = newElement;
diff --git a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
index 0995bfef53a..8b20789dfb6 100644
--- a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
+++ b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj
@@ -283,6 +283,7 @@
+
diff --git a/build.cake b/build.cake
index 11eed606dd7..67ade591d26 100644
--- a/build.cake
+++ b/build.cake
@@ -470,11 +470,13 @@ Task ("cg-uwp-build-tests")
.WithProperty("PackageCertificateThumbprint", "a59087cc92a9a8117ffdb5255eaa155748f9f852")
.WithProperty("PackageCertificateKeyFile", "Xamarin.Forms.ControlGallery.WindowsUniversal_TemporaryKey.pfx")
.WithProperty("PackageCertificatePassword", "")
+ // The platform unit tests can't run when UseDotNetNativeToolchain is set to true so we force it off here
+ .WithProperty("UseDotNetNativeToolchain", "false")
.WithRestore()
);
MSBuild("Xamarin.Forms.Core.Windows.UITests\\Xamarin.Forms.Core.Windows.UITests.csproj",
- GetMSBuildSettings().WithRestore());
+ GetMSBuildSettings(buildConfiguration:"Debug").WithRestore());
});
Task ("cg-uwp-deploy")
diff --git a/build/steps/build-windows.yml b/build/steps/build-windows.yml
index f8ccf42dbde..e1bca00f65b 100644
--- a/build/steps/build-windows.yml
+++ b/build/steps/build-windows.yml
@@ -193,12 +193,12 @@ steps:
TargetFolder: ${{ parameters.artifactsTargetFolder }}
- script: build.cmd -Target cg-uwp-build-tests -ScriptArgs '-BUILD_CONFIGURATION="$(BuildConfiguration)"'
- condition: eq(variables['BuildConfiguration'], 'Debug')
+ condition: and(eq(variables['BuildConfiguration'], 'Release'), ne('${{ parameters.includePages }}', true))
displayName: 'Build Tests and APPX'
- task: CopyFiles@2
displayName: 'Copy Appx Packages'
- condition: eq(variables['BuildConfiguration'], 'Debug')
+ condition: and(eq(variables['BuildConfiguration'], 'Release'), ne('${{ parameters.includePages }}', true))
inputs:
Contents: |
Xamarin.Forms.ControlGallery.WindowsUniversal/AppPackages/*/*
@@ -220,9 +220,9 @@ steps:
- task: CopyFiles@2
displayName: 'Copy UITest Files'
- condition: eq(variables['BuildConfiguration'], 'Debug')
+ condition: and(eq(variables['BuildConfiguration'], 'Release'), ne('${{ parameters.includePages }}', true))
inputs:
- SourceFolder: Xamarin.Forms.Core.Windows.UITests/bin/$(BuildConfiguration)/
+ SourceFolder: Xamarin.Forms.Core.Windows.UITests/bin/Debug/
TargetFolder: '$(build.artifactstagingdirectory)/UITests'
- task: CopyFiles@2