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