From f140a6be0315453d671288cc2ba5be745341ed60 Mon Sep 17 00:00:00 2001 From: Poker Date: Mon, 3 Feb 2025 12:13:50 +0800 Subject: [PATCH 1/6] DockPanel --- .../Primitives/src/DockPanel/DockPanel.cs | 93 +++++++++---------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/components/Primitives/src/DockPanel/DockPanel.cs b/components/Primitives/src/DockPanel/DockPanel.cs index 759e2262..5d7e3dc9 100644 --- a/components/Primitives/src/DockPanel/DockPanel.cs +++ b/components/Primitives/src/DockPanel/DockPanel.cs @@ -32,13 +32,15 @@ protected override Size ArrangeOverride(Size finalSize) var currentBounds = new Rect( Padding.Left, Padding.Top, - GetPositiveOrZero(finalSize.Width - Padding.Left - Padding.Right), - GetPositiveOrZero(finalSize.Height - Padding.Top - Padding.Bottom)); + Math.Max(0, finalSize.Width - Padding.Left - Padding.Right), + Math.Max(0, finalSize.Height - Padding.Top - Padding.Bottom)); var childrenCount = LastChildFill ? Children.Count - 1 : Children.Count; for (var index = 0; index < childrenCount; ++index) { var child = Children[index]; + if (child.Visibility is Visibility.Collapsed) + continue; var dock = (Dock)child.GetValue(DockProperty); double width, height; switch (dock) @@ -49,7 +51,7 @@ protected override Size ArrangeOverride(Size finalSize) child.Arrange(new Rect(currentBounds.X, currentBounds.Y, width, currentBounds.Height)); width += HorizontalSpacing; currentBounds.X += width; - currentBounds.Width = GetPositiveOrZero(currentBounds.Width - width); + currentBounds.Width = Math.Max(0, currentBounds.Width - width); break; case Dock.Top: @@ -58,7 +60,7 @@ protected override Size ArrangeOverride(Size finalSize) child.Arrange(new Rect(currentBounds.X, currentBounds.Y, currentBounds.Width, height)); height += VerticalSpacing; currentBounds.Y += height; - currentBounds.Height = GetPositiveOrZero(currentBounds.Height - height); + currentBounds.Height = Math.Max(0, currentBounds.Height - height); break; case Dock.Right: @@ -66,7 +68,7 @@ protected override Size ArrangeOverride(Size finalSize) width = Math.Min(child.DesiredSize.Width, currentBounds.Width); child.Arrange(new Rect(currentBounds.X + currentBounds.Width - width, currentBounds.Y, width, currentBounds.Height)); width += HorizontalSpacing; - currentBounds.Width = GetPositiveOrZero(currentBounds.Width - width); + currentBounds.Width = Math.Max(0, currentBounds.Width - width); break; case Dock.Bottom: @@ -74,7 +76,7 @@ protected override Size ArrangeOverride(Size finalSize) height = Math.Min(child.DesiredSize.Height, currentBounds.Height); child.Arrange(new Rect(currentBounds.X, currentBounds.Y + currentBounds.Height - height, currentBounds.Width, height)); height += VerticalSpacing; - currentBounds.Height = GetPositiveOrZero(currentBounds.Height - height); + currentBounds.Height = Math.Max(0, currentBounds.Height - height); break; } @@ -92,70 +94,60 @@ protected override Size ArrangeOverride(Size finalSize) /// protected override Size MeasureOverride(Size availableSize) { - var parentWidth = 0.0; - var parentHeight = 0.0; - var accumulatedWidth = Padding.Left + Padding.Right; - var accumulatedHeight = Padding.Top + Padding.Bottom; - - var leftSpacing = false; - var topSpacing = false; - var rightSpacing = false; - var bottomSpacing = false; + var parentWidth = 0d; + var parentHeight = 0d; + var accumulatedWidth = 0d; + var accumulatedHeight = 0d; + + var horizontalSpacing = false; + var verticalSpacing = false; var childrenCount = LastChildFill ? Children.Count - 1 : Children.Count; - + for (var index = 0; index < childrenCount; ++index) { var child = Children[index]; var childConstraint = new Size( - GetPositiveOrZero(availableSize.Width - accumulatedWidth), - GetPositiveOrZero(availableSize.Height - accumulatedHeight)); - + Math.Max(0, availableSize.Width - accumulatedWidth), + Math.Max(0, availableSize.Height - accumulatedHeight)); + child.Measure(childConstraint); var childDesiredSize = child.DesiredSize; - - switch ((Dock)child.GetValue(DockProperty)) + + switch (child.GetValue(DockProperty)) { case Dock.Left: - leftSpacing = true; - parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); - if (childConstraint.Width is not 0) - accumulatedWidth += HorizontalSpacing; - accumulatedWidth += childDesiredSize.Width; - break; - case Dock.Right: - rightSpacing = true; parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); - if (childConstraint.Width is not 0) + if (child.Visibility is Visibility.Visible) + { accumulatedWidth += HorizontalSpacing; + horizontalSpacing = true; + } + accumulatedWidth += childDesiredSize.Width; break; - + case Dock.Top: - topSpacing = true; - parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); - if (childConstraint.Height is not 0) - accumulatedHeight += VerticalSpacing; - accumulatedHeight += childDesiredSize.Height; - break; - case Dock.Bottom: - bottomSpacing = true; parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); - if (childConstraint.Height is not 0) + if (child.Visibility is Visibility.Visible) + { accumulatedHeight += VerticalSpacing; + verticalSpacing = true; + } + accumulatedHeight += childDesiredSize.Height; break; } } - + if (LastChildFill) { var child = Children[Children.Count - 1]; var childConstraint = new Size( - GetPositiveOrZero(availableSize.Width - accumulatedWidth), - GetPositiveOrZero(availableSize.Height - accumulatedHeight)); - + Math.Max(0, availableSize.Width - accumulatedWidth), + Math.Max(0, availableSize.Height - accumulatedHeight)); + child.Measure(childConstraint); var childDesiredSize = child.DesiredSize; parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); @@ -165,16 +157,15 @@ protected override Size MeasureOverride(Size availableSize) } else { - if (leftSpacing || rightSpacing) + if (horizontalSpacing) accumulatedWidth -= HorizontalSpacing; - if (bottomSpacing || topSpacing) + if (verticalSpacing) accumulatedHeight -= VerticalSpacing; } - - parentWidth = Math.Min(availableSize.Width, Math.Max(parentWidth, accumulatedWidth)); - parentHeight = Math.Min(availableSize.Height, Math.Max(parentHeight, accumulatedHeight)); + + // Make sure the final accumulated size is reflected in parentSize. + parentWidth = Math.Max(parentWidth, accumulatedWidth); + parentHeight = Math.Max(parentHeight, accumulatedHeight); return new Size(parentWidth, parentHeight); } - - private static double GetPositiveOrZero(double value) => Math.Max(value, 0); } From dc781585619523768bb58fb3a36890d03795ed85 Mon Sep 17 00:00:00 2001 From: Poker Date: Thu, 20 Feb 2025 02:27:51 +0800 Subject: [PATCH 2/6] Update DockPanel.cs --- components/Primitives/src/DockPanel/DockPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Primitives/src/DockPanel/DockPanel.cs b/components/Primitives/src/DockPanel/DockPanel.cs index 5d7e3dc9..c536b8c8 100644 --- a/components/Primitives/src/DockPanel/DockPanel.cs +++ b/components/Primitives/src/DockPanel/DockPanel.cs @@ -82,7 +82,7 @@ protected override Size ArrangeOverride(Size finalSize) } } - if (LastChildFill) + if (LastChildFill && Children.Count > 0) { var child = Children[Children.Count - 1]; child.Arrange(new Rect(currentBounds.X, currentBounds.Y, currentBounds.Width, currentBounds.Height)); @@ -141,7 +141,7 @@ protected override Size MeasureOverride(Size availableSize) } } - if (LastChildFill) + if (LastChildFill && Children.Count > 0) { var child = Children[Children.Count - 1]; var childConstraint = new Size( From 3792d614839ea69dfb65d44986c6a19cda03b7a9 Mon Sep 17 00:00:00 2001 From: Arlo Date: Tue, 25 Mar 2025 18:53:57 -0500 Subject: [PATCH 3/6] Add basic unit tests for empty DockPanel with LastChildFill = true. Validated repro for fix given in https://github.com/CommunityToolkit/Windows/pull/618 --- .../tests/DockPanel/DockPanelSample.xaml | 18 ++++++++++++++++++ .../tests/DockPanel/DockPanelSample.xaml.cs | 14 ++++++++++++++ .../tests/DockPanel/DockPanelTests.cs | 16 ++++++++++++++++ .../tests/Primitives.Tests.projitems | 8 ++++++++ 4 files changed, 56 insertions(+) create mode 100644 components/Primitives/tests/DockPanel/DockPanelSample.xaml create mode 100644 components/Primitives/tests/DockPanel/DockPanelSample.xaml.cs create mode 100644 components/Primitives/tests/DockPanel/DockPanelTests.cs diff --git a/components/Primitives/tests/DockPanel/DockPanelSample.xaml b/components/Primitives/tests/DockPanel/DockPanelSample.xaml new file mode 100644 index 00000000..13b5aa17 --- /dev/null +++ b/components/Primitives/tests/DockPanel/DockPanelSample.xaml @@ -0,0 +1,18 @@ + + + + + diff --git a/components/Primitives/tests/DockPanel/DockPanelSample.xaml.cs b/components/Primitives/tests/DockPanel/DockPanelSample.xaml.cs new file mode 100644 index 00000000..147cb354 --- /dev/null +++ b/components/Primitives/tests/DockPanel/DockPanelSample.xaml.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace PrimitivesTests; + +public sealed partial class DockPanelSample : Page +{ + public DockPanelSample() + { + this.InitializeComponent(); + } +} + diff --git a/components/Primitives/tests/DockPanel/DockPanelTests.cs b/components/Primitives/tests/DockPanel/DockPanelTests.cs new file mode 100644 index 00000000..ecd15991 --- /dev/null +++ b/components/Primitives/tests/DockPanel/DockPanelTests.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Tests; +using CommunityToolkit.Tooling.TestGen; + +namespace PrimitivesTests; + +[TestClass] +public partial class DockPanelTests : VisualUITestBase +{ + [UIThreadTestMethod] + public void DockPanelTest(DockPanelSample page) + { + var dockPanel = page.FindDescendant(); + + Assert.IsNotNull(dockPanel, "Couldn't find DockPanel"); + } +} diff --git a/components/Primitives/tests/Primitives.Tests.projitems b/components/Primitives/tests/Primitives.Tests.projitems index 74ba50a3..39e21d6d 100644 --- a/components/Primitives/tests/Primitives.Tests.projitems +++ b/components/Primitives/tests/Primitives.Tests.projitems @@ -9,6 +9,10 @@ PrimitivesTests + + DockPanelSample.xaml + + %(Filename) @@ -35,6 +39,10 @@ + + Designer + MSBuild:Compile + Designer MSBuild:Compile From df2e23bf5d1a60a3ec5ad1e467e51b7f510672ab Mon Sep 17 00:00:00 2001 From: Arlo Date: Tue, 25 Mar 2025 20:10:28 -0500 Subject: [PATCH 4/6] Fix button click event for adding stretch child in DockPanelSample --- components/Primitives/samples/DockPanelSample.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Primitives/samples/DockPanelSample.xaml b/components/Primitives/samples/DockPanelSample.xaml index 8cecbb93..c7b1624c 100644 --- a/components/Primitives/samples/DockPanelSample.xaml +++ b/components/Primitives/samples/DockPanelSample.xaml @@ -1,4 +1,4 @@ - +