Skip to content

Fix: DockPanel measure fix #618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/Primitives/samples/DockPanelSample.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- 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. -->
<!-- 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. -->
<Page x:Class="PrimitivesExperiment.Samples.DockPanelSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand Down Expand Up @@ -27,7 +27,7 @@
Content="Add Bottom child" />
<Button Click="AddRightDock"
Content="Add Right child" />
<Button Click="AddRightDock"
<Button Click="AddStretchDock"
Content="Add Stretch child" />
<Button Click="ClearAllDock"
Content="Clear all" />
Expand Down
97 changes: 44 additions & 53 deletions components/Primitives/src/DockPanel/DockPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand All @@ -58,29 +60,29 @@ 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:

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:

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;
}
}

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));
Expand All @@ -92,70 +94,60 @@ protected override Size ArrangeOverride(Size finalSize)
/// <inheritdoc />
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)

if (LastChildFill && Children.Count > 0)
{
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);
Expand All @@ -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);
}
17 changes: 17 additions & 0 deletions components/Primitives/tests/DockPanel/DockPanelSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Page x:Class="PrimitivesTests.DockPanelSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:PrimitivesTests"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d">

<controls:DockPanel x:Name="SampleDockPanel"
Grid.Column="1"
HorizontalSpacing="5"
LastChildFill="True"
VerticalSpacing="5" />
</Page>
14 changes: 14 additions & 0 deletions components/Primitives/tests/DockPanel/DockPanelSample.xaml.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}

20 changes: 20 additions & 0 deletions components/Primitives/tests/DockPanel/DockPanelTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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.

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<CommunityToolkit.WinUI.Controls.DockPanel>();

Assert.IsNotNull(dockPanel, "Couldn't find DockPanel");
}
}
8 changes: 8 additions & 0 deletions components/Primitives/tests/Primitives.Tests.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
<Import_RootNamespace>PrimitivesTests</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)DockPanel\DockPanelSample.xaml.cs">
<DependentUpon>DockPanelSample.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)DockPanel\DockPanelTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SwitchPresenter\SwitchConverterBrushSample.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
Expand All @@ -35,6 +39,10 @@
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)DockPanel\DockPanelSample.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)UniformGrid\AutoLayoutFixedElementZeroZeroSpecialPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
Loading