From 48825c84aafa8b3d8a729921d3735e07fb5f2218 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 6 Jun 2020 01:04:19 +0200 Subject: [PATCH 01/26] add sample page + implementation skeleton --- .../Microsoft.Toolkit.Uwp.SampleApp.csproj | 13 +- .../MultiColumnsStackPanel.png | Bin 0 -> 888 bytes .../MultiColumnsStackPanelCode.bind | 33 +++++ .../MultiColumnsStackPanelPage.xaml | 34 +++++ .../MultiColumnsStackPanelPage.xaml.cs | 16 +++ .../SamplePages/samples.json | 28 +++-- .../MultiColumnsStackPanel.cs | 119 ++++++++++++++++++ 7 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanel.png create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index fb9c276db82..9b6a1ca32d1 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -271,6 +271,7 @@ + @@ -516,6 +517,9 @@ + + MultiColumnsStackPanelPage.xaml + TilesBrushPage.xaml @@ -994,6 +998,13 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile Designer @@ -1634,4 +1645,4 @@ - + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanel.png b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..3f3e3bf6772f63fe808e1047dd9e6d3c7fff8e9d GIT binary patch literal 888 zcmeAS@N?(olHy`uVBq!ia0y~yU{nCI4{)#n$t4^1Z39v)#ZI0f96(URkAu7PQj6y$_fBxp0HKd|XIq#U_b{$x?H_fgB$=fyf#$6a`T{`vFg*Lf8_$S(N( zcb^^8o@1YX?)e*Qe&95xzyv`B1!V^Zw}yru21ZFnCL<=66c&yX90C(|J_+qP{&=I_ z0}*+7`PaW>f-QWlfYoQp**#2@GqxAUA(oU@UWSH=_5`{>%>;esqN zGuM1!qwS3rwmucCVTi025x6bH*r-fYssKjyOz-Cw4aGAaGxQam6c#w}zk-P= q2x};VLhk + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml new file mode 100644 index 00000000000..fa09c6afb72 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml.cs new file mode 100644 index 00000000000..aba3e8ca87e --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml.cs @@ -0,0 +1,16 @@ +// 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 Windows.UI.Xaml.Controls; + +namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages +{ + /// + /// A page that shows how to use the MultiColumnsStackPanel. + /// + public sealed partial class MultiColumnsStackPanelPage : Page + { + public MultiColumnsStackPanelPage() => InitializeComponent(); + } +} diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index 4839ba62fd9..b65a967d288 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -231,6 +231,16 @@ "Icon": "/SamplePages/WrapPanel/WrapPanel.png", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/WrapPanel.md" }, + { + "Name": "MultiColumnsStackPanel", + "Type": "MultiColumnsStackPanelPage", + "Subcategory": "Layout", + "About": "The MultiColumnsStackPanel Control positions child elements .", + "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel", + "XamlCodeFile": "MultiColumnsStackPanelCode.bind", + "Icon": "/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanel.png", + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/WrapPanel.md" + }, { "Name": "WrapLayout", "Type": "WrapLayoutPage", @@ -1252,15 +1262,15 @@ "XamlCodeFile": "OnDeviceXaml.bind", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/extensions/OnDeviceMarkup.md" }, - { - "Name": "IconExtensions", - "Type": "IconExtensionsPage", - "About": "Markup extensions to easily create various types of icons.", - "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI/Extensions/Markup/FontIconExtension", - "XamlCodeFile": "IconExtensionsXaml.bind", - "Icon": "/Assets/Helpers.png", - "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/extensions/IconExtensions.md" - } + { + "Name": "IconExtensions", + "Type": "IconExtensionsPage", + "About": "Markup extensions to easily create various types of icons.", + "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI/Extensions/Markup/FontIconExtension", + "XamlCodeFile": "IconExtensionsXaml.bind", + "Icon": "/Assets/Helpers.png", + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/extensions/IconExtensions.md" + } ] }, { diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs new file mode 100644 index 00000000000..591df34fdb0 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -0,0 +1,119 @@ +// 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 Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// positions its child elements vertically in one or several columns based on the property. + /// + public class MultiColumnsStackPanel : Panel + { + /// + /// The DP to store the MaxColumnWidth value. + /// + public static readonly DependencyProperty MaxColumnWidthProperty = DependencyProperty.Register( + nameof(MaxColumnWidth), + typeof(double), + typeof(MultiColumnsStackPanel), + new PropertyMetadata(0.0, OnLayoutPropertyChanged)); + + /// + /// The DP to store the ColumnsSpacing value. + /// + public static readonly DependencyProperty ColumnsSpacingProperty = DependencyProperty.Register( + nameof(ColumnsSpacing), + typeof(double), + typeof(MultiColumnsStackPanel), + new PropertyMetadata(0.0, OnLayoutPropertyChanged)); + + /// + /// The DP to store the ItemsSpacing value. + /// + public static readonly DependencyProperty ItemsSpacingProperty = DependencyProperty.Register( + nameof(ItemsSpacing), + typeof(double), + typeof(MultiColumnsStackPanel), + new PropertyMetadata(0.0, OnLayoutPropertyChanged)); + + /// + /// The DP to store the HorizontalContentAlignment value. + /// + public static readonly DependencyProperty HorizontalContentAlignmentProperty = DependencyProperty.Register( + nameof(HorizontalContentAlignment), + typeof(HorizontalAlignment), + typeof(MultiColumnsStackPanel), + new PropertyMetadata(HorizontalAlignment.Stretch, OnLayoutPropertyChanged)); + + /// + /// Gets or sets the maximum width for the columns. + /// If the value is 0, it will display a single column (like a vertical ). + /// + public double MaxColumnWidth + { + get => (double)GetValue(MaxColumnWidthProperty); + set => SetValue(MaxColumnWidthProperty, value); + } + + /// + /// Gets or sets the spacing between two columns. + /// + public double ColumnsSpacing + { + get => (double)GetValue(ColumnsSpacingProperty); + set => SetValue(ColumnsSpacingProperty, value); + } + + /// + /// Gets or sets the spacing between two items. + /// + public double ItemsSpacing + { + get => (double)GetValue(ItemsSpacingProperty); + set => SetValue(ItemsSpacingProperty, value); + } + + /// + /// Gets or sets the horizontal alignment of the control's content. + /// + public HorizontalAlignment HorizontalContentAlignment + { + get => (HorizontalAlignment)GetValue(HorizontalContentAlignmentProperty); + set => SetValue(HorizontalContentAlignmentProperty, value); + } + + private static void OnLayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (MultiColumnsStackPanel)d; + + control.InvalidateMeasure(); + control.InvalidateArrange(); + } + + /// + protected override Size MeasureOverride(Size availableSize) + { + foreach (var child in Children) + { + child.Measure(availableSize); + } + + return availableSize; + } + + /// + protected override Size ArrangeOverride(Size finalSize) + { + foreach (var child in Children) + { + child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); + } + + return finalSize; + } + } +} From e05e47cba620d94a1696cd17a7e3c6cb5857a180 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 7 Jun 2020 00:10:29 +0200 Subject: [PATCH 02/26] add properties binding --- .../MultiColumnsStackPanelCode.bind | 17 ++++++++++++++--- .../MultiColumnsStackPanelPage.xaml | 11 ++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index 178b039b0a9..ee8cb31883a 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -6,9 +6,11 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> - + @@ -29,5 +31,14 @@ + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index fa09c6afb72..516623a7d4d 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -9,7 +9,7 @@ + MaxColumnWidth="240"> @@ -30,5 +30,14 @@ + + + + + + + + + From 9da84063e4f1803ecd28c2e76960ce1dca22bdff Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 7 Jun 2020 00:10:46 +0200 Subject: [PATCH 03/26] first drop of implementation --- .../MultiColumnsStackPanel.cs | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 591df34fdb0..6d49c40b0e9 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Linq; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -97,23 +99,68 @@ private static void OnLayoutPropertyChanged(DependencyObject d, DependencyProper /// protected override Size MeasureOverride(Size availableSize) { + // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. + var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(availableSize); + var childAvailableSize = new Size(columnsWidth, availableSize.Height); foreach (var child in Children) { - child.Measure(availableSize); + child.Measure(childAvailableSize); } - return availableSize; + // We get the number of available columns that we can fill. + var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); + + // var availableCombinedColumnsHeight = availableSize.Height * columnsCount; <= This is not needed... + var requiredColumns = Math.Ceiling(totalChildrenHeight / availableSize.Height); + + var requiredColumnsWidth = requiredColumns * columnsWidth; + var requiredSpacingWidth = Math.Max(0, requiredColumns - 1) * ColumnsSpacing; + return new Size( + requiredColumnsWidth + requiredSpacingWidth, + totalChildrenHeight / requiredColumns); // <-- this will have to be improved. We need to get the height of the tallest column. Need to handle ItemsSpacing } /// protected override Size ArrangeOverride(Size finalSize) { + // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. + var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); + + var currentColumn = 0; + var currentHeight = 0.0; + var rect = new Rect(0, 0, columnsWidth, 0); foreach (var child in Children) { - child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); + // <=== Need to handle ItemsSpacing. + rect.Height = child.DesiredSize.Height; + rect.Y = currentHeight; + currentHeight += rect.Height; + + if (currentHeight >= finalSize.Height) + { + currentColumn++; + currentHeight = rect.Height; + rect.X += columnsWidth + ColumnsSpacing; + rect.Y = 0; + } + + child.Arrange(rect); } return finalSize; } + + private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) + { + var columnsWidth = MaxColumnWidth > 0 ? Math.Min(MaxColumnWidth, availableSize.Width) : availableSize.Width; + var columnsCount = 1; + if (columnsWidth < availableSize.Width) + { + var additionalColumns = (int)((availableSize.Width - columnsWidth) / (columnsWidth + ColumnsSpacing)); + columnsCount += additionalColumns; + } + + return (columnsCount, columnsWidth); + } } } From 112a5d39c985d6e0ce5ce79208255d640ca74bc4 Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 8 Jun 2020 23:40:06 +0200 Subject: [PATCH 04/26] improve arrange logic --- .../MultiColumnsStackPanelCode.bind | 72 ++++++++++--------- .../MultiColumnsStackPanelPage.xaml | 68 +++++++++--------- .../MultiColumnsStackPanel.cs | 30 ++++++-- 3 files changed, 96 insertions(+), 74 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index ee8cb31883a..45c93013713 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -6,39 +6,41 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index 516623a7d4d..011d320a540 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -7,37 +7,39 @@ Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 6d49c40b0e9..342edd2728d 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -101,7 +101,7 @@ protected override Size MeasureOverride(Size availableSize) { // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(availableSize); - var childAvailableSize = new Size(columnsWidth, availableSize.Height); + var childAvailableSize = new Size(columnsWidth, double.PositiveInfinity); foreach (var child in Children) { child.Measure(childAvailableSize); @@ -113,11 +113,11 @@ protected override Size MeasureOverride(Size availableSize) // var availableCombinedColumnsHeight = availableSize.Height * columnsCount; <= This is not needed... var requiredColumns = Math.Ceiling(totalChildrenHeight / availableSize.Height); - var requiredColumnsWidth = requiredColumns * columnsWidth; - var requiredSpacingWidth = Math.Max(0, requiredColumns - 1) * ColumnsSpacing; + var requiredColumnsWidth = columnsCount * columnsWidth; + var requiredSpacingWidth = Math.Max(0, columnsCount - 1) * ColumnsSpacing; return new Size( requiredColumnsWidth + requiredSpacingWidth, - totalChildrenHeight / requiredColumns); // <-- this will have to be improved. We need to get the height of the tallest column. Need to handle ItemsSpacing + totalChildrenHeight / columnsCount); // <-- this will have to be improved. We need to get the height of the tallest column. Need to handle ItemsSpacing } /// @@ -126,9 +126,20 @@ protected override Size ArrangeOverride(Size finalSize) // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); + // We split the items across all the columns + var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); + var totalAvailableColumnsHeight = finalSize.Height * columnsCount; + var columnHeight = finalSize.Height; + if (totalChildrenHeight > totalAvailableColumnsHeight) + { + // We cannot fit all our children in the columns we have. We will have to overflow. + columnHeight = totalChildrenHeight / columnsCount; + } + var currentColumn = 0; var currentHeight = 0.0; var rect = new Rect(0, 0, columnsWidth, 0); + var maxCurrentHeight = 0.0; foreach (var child in Children) { // <=== Need to handle ItemsSpacing. @@ -136,18 +147,25 @@ protected override Size ArrangeOverride(Size finalSize) rect.Y = currentHeight; currentHeight += rect.Height; - if (currentHeight >= finalSize.Height) + if (currentHeight >= columnHeight) { + maxCurrentHeight = Math.Max(maxCurrentHeight, currentHeight - rect.Height); + currentColumn++; currentHeight = rect.Height; rect.X += columnsWidth + ColumnsSpacing; rect.Y = 0; + } child.Arrange(rect); } - return finalSize; + maxCurrentHeight = Math.Max(maxCurrentHeight, currentHeight); + + return new Size( + rect.X + columnsWidth, + maxCurrentHeight); } private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) From e70cf763d05e2f639733da035c557662d2e219fb Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 16 Jun 2020 23:35:01 +0200 Subject: [PATCH 05/26] algorithm is almost working (but not efficient) --- .../MultiColumnsStackPanelPage.xaml | 4 +- .../MultiColumnsStackPanel.cs | 110 ++++++++++++------ 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index 011d320a540..35b8d8a1ac2 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -8,7 +8,9 @@ mc:Ignorable="d"> - diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 342edd2728d..9240d380c82 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Linq; using Windows.Foundation; using Windows.UI.Xaml; @@ -107,17 +108,71 @@ protected override Size MeasureOverride(Size availableSize) child.Measure(childAvailableSize); } - // We get the number of available columns that we can fill. - var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); + // We evaluate how the children are filling the columns to get the size that we will use. + var columnHeight = GetColumnHeight(columnsCount, availableSize); + var columnsItemsHeights = new List[columnsCount]; + for (var i = 0; i < columnsCount; i++) + { + columnsItemsHeights[i] = new List(); + } - // var availableCombinedColumnsHeight = availableSize.Height * columnsCount; <= This is not needed... - var requiredColumns = Math.Ceiling(totalChildrenHeight / availableSize.Height); + var overflowItemsHeights = new List(); + var adjustementColumnIndex = 0; + while (true) + { + var height = 0.0; + var maxHeigth = 0.0; + var columnsIndex = 0; + foreach (var child in Children) + { + if (columnsIndex < columnsCount) + { + columnsItemsHeights[columnsIndex].Add(child.DesiredSize.Height); + } + else + { + overflowItemsHeights.Add(child.DesiredSize.Height); + } + + height += child.DesiredSize.Height; + if (height > columnHeight) + { + maxHeigth = Math.Max(maxHeigth, height); + height = 0; + columnsIndex++; + } + } - var requiredColumnsWidth = columnsCount * columnsWidth; - var requiredSpacingWidth = Math.Max(0, columnsCount - 1) * ColumnsSpacing; - return new Size( - requiredColumnsWidth + requiredSpacingWidth, - totalChildrenHeight / columnsCount); // <-- this will have to be improved. We need to get the height of the tallest column. Need to handle ItemsSpacing + var requiredColumnsCount = columnsItemsHeights.TakeWhile(x => x.Any()).Count(); + var requiredColumnsWidth = requiredColumnsCount * columnsWidth; + var requiredSpacingWidth = Math.Max(0, requiredColumnsCount - 1) * ColumnsSpacing; + + if (overflowItemsHeights.Count == 0) + { + // No overflow, we've been able to put all our items in our columns. + return new Size( + requiredColumnsWidth + requiredSpacingWidth, + maxHeigth); // <-- Need to handle ItemsSpacing + } + + // We move the first item of the second column to the first one + columnsItemsHeights[adjustementColumnIndex].Add(columnsItemsHeights[adjustementColumnIndex + 1].FirstOrDefault()); + columnsItemsHeights[adjustementColumnIndex + 1].RemoveAt(0); + } + } + + private double GetColumnHeight(int columnsCount, Size availableSize) + { + var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); + //var availableColumnsHeight = columnsCount * availableSize.Height; + //if (totalChildrenHeight <= availableColumnsHeight) + //{ + // // We have enough space for all our items + // return Math.Ceiling(availableSize.Height); + //} + + // Not enough place for all items. We required longer columns + return Math.Ceiling(totalChildrenHeight / columnsCount); } /// @@ -127,45 +182,34 @@ protected override Size ArrangeOverride(Size finalSize) var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); // We split the items across all the columns - var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); - var totalAvailableColumnsHeight = finalSize.Height * columnsCount; - var columnHeight = finalSize.Height; - if (totalChildrenHeight > totalAvailableColumnsHeight) - { - // We cannot fit all our children in the columns we have. We will have to overflow. - columnHeight = totalChildrenHeight / columnsCount; - } + var columnHeight = GetColumnHeight(columnsCount, finalSize); - var currentColumn = 0; - var currentHeight = 0.0; + var height = 0.0; + var maxHeigth = 0.0; + var requiredColumnsCount = 0; var rect = new Rect(0, 0, columnsWidth, 0); - var maxCurrentHeight = 0.0; foreach (var child in Children) { - // <=== Need to handle ItemsSpacing. rect.Height = child.DesiredSize.Height; - rect.Y = currentHeight; - currentHeight += rect.Height; + rect.Y = height; - if (currentHeight >= columnHeight) + child.Arrange(rect); + + height += child.DesiredSize.Height; + if (height >= columnHeight) { - maxCurrentHeight = Math.Max(maxCurrentHeight, currentHeight - rect.Height); + maxHeigth = Math.Max(maxHeigth, height); + height = 0; + requiredColumnsCount++; - currentColumn++; - currentHeight = rect.Height; rect.X += columnsWidth + ColumnsSpacing; rect.Y = 0; - } - - child.Arrange(rect); } - maxCurrentHeight = Math.Max(maxCurrentHeight, currentHeight); - return new Size( rect.X + columnsWidth, - maxCurrentHeight); + maxHeigth); } private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) From 77cba20b15f6befc3d91d7c0310119c4feff9816 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 17 Jun 2020 23:34:25 +0200 Subject: [PATCH 06/26] rewrite algorithm --- .../MultiColumnsStackPanel.cs | 184 +++++++++++------- 1 file changed, 111 insertions(+), 73 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 9240d380c82..4fe234a1d40 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Linq; using Windows.Foundation; using Windows.UI.Xaml; @@ -110,106 +109,145 @@ protected override Size MeasureOverride(Size availableSize) // We evaluate how the children are filling the columns to get the size that we will use. var columnHeight = GetColumnHeight(columnsCount, availableSize); - var columnsItemsHeights = new List[columnsCount]; - for (var i = 0; i < columnsCount; i++) - { - columnsItemsHeights[i] = new List(); - } + var columnsData = DoLayout(columnsCount, columnHeight); + + var size = GetFinalSize(columnsData, columnsWidth); + return size; + } + + /// + protected override Size ArrangeOverride(Size finalSize) + { + // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. + var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); - var overflowItemsHeights = new List(); - var adjustementColumnIndex = 0; - while (true) + // We split the items across all the columns + var columnHeight = GetColumnHeight(columnsCount, finalSize); + var columnsData = DoLayout(columnsCount, columnHeight); + + var rect = new Rect(0, 0, columnsWidth, 0); + var height = 0.0; + var currentColumn = 0; + for (var childIndex = 0; childIndex < Children.Count; childIndex++) { - var height = 0.0; - var maxHeigth = 0.0; - var columnsIndex = 0; - foreach (var child in Children) - { - if (columnsIndex < columnsCount) - { - columnsItemsHeights[columnsIndex].Add(child.DesiredSize.Height); - } - else - { - overflowItemsHeights.Add(child.DesiredSize.Height); - } - height += child.DesiredSize.Height; - if (height > columnHeight) - { - maxHeigth = Math.Max(maxHeigth, height); - height = 0; - columnsIndex++; - } - } + var child = Children[childIndex]; + rect.Y = height; + rect.Height = child.DesiredSize.Height; - var requiredColumnsCount = columnsItemsHeights.TakeWhile(x => x.Any()).Count(); - var requiredColumnsWidth = requiredColumnsCount * columnsWidth; - var requiredSpacingWidth = Math.Max(0, requiredColumnsCount - 1) * ColumnsSpacing; + child.Arrange(rect); - if (overflowItemsHeights.Count == 0) + height += child.DesiredSize.Height; + if (childIndex == columnsData[currentColumn].LastChildIndex) { - // No overflow, we've been able to put all our items in our columns. - return new Size( - requiredColumnsWidth + requiredSpacingWidth, - maxHeigth); // <-- Need to handle ItemsSpacing - } + // We've reached the last item for the current column. We move to the next one. + height = 0.0; + currentColumn++; - // We move the first item of the second column to the first one - columnsItemsHeights[adjustementColumnIndex].Add(columnsItemsHeights[adjustementColumnIndex + 1].FirstOrDefault()); - columnsItemsHeights[adjustementColumnIndex + 1].RemoveAt(0); + rect.X += columnsWidth + ColumnsSpacing; + rect.Y = 0; + } } + + var size = GetFinalSize(columnsData, columnsWidth); + return size; } private double GetColumnHeight(int columnsCount, Size availableSize) { var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); - //var availableColumnsHeight = columnsCount * availableSize.Height; - //if (totalChildrenHeight <= availableColumnsHeight) - //{ - // // We have enough space for all our items - // return Math.Ceiling(availableSize.Height); - //} - - // Not enough place for all items. We required longer columns + var availableColumnsHeight = columnsCount * availableSize.Height; + if (totalChildrenHeight <= availableColumnsHeight) + { + // We have enough space for all our items, we try with the available height + return Math.Ceiling(availableSize.Height); + } + + // Not enough place for all items. We try with a balanced split. return Math.Ceiling(totalChildrenHeight / columnsCount); } - /// - protected override Size ArrangeOverride(Size finalSize) + private struct ColumnData { - // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. - var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); + public int LastChildIndex { get; set; } - // We split the items across all the columns - var columnHeight = GetColumnHeight(columnsCount, finalSize); + public double ColumnHeight { get; set; } + } - var height = 0.0; - var maxHeigth = 0.0; - var requiredColumnsCount = 0; - var rect = new Rect(0, 0, columnsWidth, 0); - foreach (var child in Children) + private ColumnData[] DoLayout(int columnsCount, double targetHeight) + { + var columnsData = new ColumnData[columnsCount]; + + var currentColumnIndex = 0; + var childIndex = 0; + for (; childIndex < Children.Count; childIndex++) { - rect.Height = child.DesiredSize.Height; - rect.Y = height; + columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; + if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) + { + // We have pass the end, we move to the next column. + columnsData[currentColumnIndex].LastChildIndex = childIndex; + currentColumnIndex++; - child.Arrange(rect); + if (currentColumnIndex >= columnsData.Length) + { + // We have filled our last column. We stop + break; + } + } + } - height += child.DesiredSize.Height; - if (height >= columnHeight) + columnsData[currentColumnIndex].LastChildIndex = childIndex; + + while (childIndex < Children.Count) + { + // We have remaining items but no more space in our targetHeight height columns. + // We move the first items of each column to the previous one. + columnsData[0].LastChildIndex++; + var nextChildHeight = Children[columnsData[0].LastChildIndex].DesiredSize.Height; + columnsData[0].ColumnHeight += nextChildHeight; + + columnsData[1].ColumnHeight -= nextChildHeight; + + // We adjust the other columns so we first reset our data and restart the loop + for (var i = 1; i < columnsCount; i++) { - maxHeigth = Math.Max(maxHeigth, height); - height = 0; - requiredColumnsCount++; + columnsData[i].ColumnHeight = 0.0; + columnsData[i].LastChildIndex = 0; + } - rect.X += columnsWidth + ColumnsSpacing; - rect.Y = 0; + currentColumnIndex = 1; + childIndex = columnsData[0].LastChildIndex + 1; + for (; childIndex < Children.Count; childIndex++) + { + columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; + if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) + { + // We have pass the end, we move to the next column. + columnsData[currentColumnIndex].LastChildIndex = childIndex; + currentColumnIndex++; + + if (currentColumnIndex >= columnsData.Length) + { + // We have filled our last column. We stop + break; + } + } } } + return columnsData; + } + + private Size GetFinalSize(ColumnData[] columnsData, double columnWidth) + { + var requiredColumnsCount = columnsData.TakeWhile(cd => cd.LastChildIndex > 0).Count(); + var requiredColumnsWidth = requiredColumnsCount * columnWidth; + var requiredSpacingWidth = Math.Max(0, requiredColumnsCount - 1) * ColumnsSpacing; + var maxHeight = columnsData.Max(cd => cd.ColumnHeight); return new Size( - rect.X + columnsWidth, - maxHeigth); + requiredColumnsWidth + requiredSpacingWidth, + maxHeight); } private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) From b5aa4fc2500b2889cb5c620e323d6b9c16551ecf Mon Sep 17 00:00:00 2001 From: Vincent Date: Thu, 18 Jun 2020 00:23:33 +0200 Subject: [PATCH 07/26] algorithm is working but partition is not optimal --- .../MultiColumnsStackPanel.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 4fe234a1d40..2f008193503 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -182,11 +182,13 @@ private ColumnData[] DoLayout(int columnsCount, double targetHeight) var childIndex = 0; for (; childIndex < Children.Count; childIndex++) { + columnsData[currentColumnIndex].LastChildIndex = childIndex; columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) { // We have pass the end, we move to the next column. - columnsData[currentColumnIndex].LastChildIndex = childIndex; + columnsData[currentColumnIndex].LastChildIndex = childIndex - 1; // TODO: handle the case of super big items that do not fit. + columnsData[currentColumnIndex].ColumnHeight -= Children[childIndex].DesiredSize.Height; currentColumnIndex++; if (currentColumnIndex >= columnsData.Length) @@ -194,11 +196,13 @@ private ColumnData[] DoLayout(int columnsCount, double targetHeight) // We have filled our last column. We stop break; } + + // We fill the data for our next column + columnsData[currentColumnIndex].LastChildIndex = childIndex; + columnsData[currentColumnIndex].ColumnHeight = Children[childIndex].DesiredSize.Height; } } - columnsData[currentColumnIndex].LastChildIndex = childIndex; - while (childIndex < Children.Count) { // We have remaining items but no more space in our targetHeight height columns. @@ -209,6 +213,9 @@ private ColumnData[] DoLayout(int columnsCount, double targetHeight) columnsData[1].ColumnHeight -= nextChildHeight; + // We get our new target height + targetHeight = columnsData[0].ColumnHeight; // columnsData.Max(cd => cd.ColumnHeight); we do not pick max to have a better alignment. + // We adjust the other columns so we first reset our data and restart the loop for (var i = 1; i < columnsCount; i++) { @@ -220,11 +227,13 @@ private ColumnData[] DoLayout(int columnsCount, double targetHeight) childIndex = columnsData[0].LastChildIndex + 1; for (; childIndex < Children.Count; childIndex++) { + columnsData[currentColumnIndex].LastChildIndex = childIndex; columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) { // We have pass the end, we move to the next column. - columnsData[currentColumnIndex].LastChildIndex = childIndex; + columnsData[currentColumnIndex].LastChildIndex = childIndex - 1; // TODO: handle the case of super big items that do not fit. + columnsData[currentColumnIndex].ColumnHeight -= Children[childIndex].DesiredSize.Height; currentColumnIndex++; if (currentColumnIndex >= columnsData.Length) @@ -232,6 +241,10 @@ private ColumnData[] DoLayout(int columnsCount, double targetHeight) // We have filled our last column. We stop break; } + + // We fill the data for our next column + columnsData[currentColumnIndex].LastChildIndex = childIndex; + columnsData[currentColumnIndex].ColumnHeight = Children[childIndex].DesiredSize.Height; } } } From d60ed8306c12a3479932fa85a17d70a6e5fa5692 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 27 Jun 2020 23:47:41 +0200 Subject: [PATCH 08/26] fix algorithm --- .../MultiColumnsStackPanel.cs | 198 +++++++++--------- 1 file changed, 96 insertions(+), 102 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 2f008193503..bde793d597e 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -99,7 +99,7 @@ private static void OnLayoutPropertyChanged(DependencyObject d, DependencyProper /// protected override Size MeasureOverride(Size availableSize) { - // We measure all our children with the minimum width between MaxColumnWidth and availableSize.Width. + // We measure all our children with our column width. We let them have the height they want. var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(availableSize); var childAvailableSize = new Size(columnsWidth, double.PositiveInfinity); foreach (var child in Children) @@ -108,11 +108,8 @@ protected override Size MeasureOverride(Size availableSize) } // We evaluate how the children are filling the columns to get the size that we will use. - var columnHeight = GetColumnHeight(columnsCount, availableSize); - var columnsData = DoLayout(columnsCount, columnHeight); - - var size = GetFinalSize(columnsData, columnsWidth); - return size; + var (_, columnHeight) = Partition(columnsCount, availableSize.Height); + return GetSize(columnsCount, columnsWidth, columnHeight); } /// @@ -122,15 +119,13 @@ protected override Size ArrangeOverride(Size finalSize) var (columnsCount, columnsWidth) = GetAvailableColumnsInformation(finalSize); // We split the items across all the columns - var columnHeight = GetColumnHeight(columnsCount, finalSize); - var columnsData = DoLayout(columnsCount, columnHeight); + var (columnLastIndex, columnHeight) = Partition(columnsCount, finalSize.Height); var rect = new Rect(0, 0, columnsWidth, 0); var height = 0.0; - var currentColumn = 0; + var currentColumnIndex = 0; for (var childIndex = 0; childIndex < Children.Count; childIndex++) { - var child = Children[childIndex]; rect.Y = height; rect.Height = child.DesiredSize.Height; @@ -138,129 +133,128 @@ protected override Size ArrangeOverride(Size finalSize) child.Arrange(rect); height += child.DesiredSize.Height; - if (childIndex == columnsData[currentColumn].LastChildIndex) + if (childIndex == columnLastIndex[currentColumnIndex]) { // We've reached the last item for the current column. We move to the next one. height = 0.0; - currentColumn++; + currentColumnIndex++; rect.X += columnsWidth + ColumnsSpacing; rect.Y = 0; } } - var size = GetFinalSize(columnsData, columnsWidth); - return size; + return GetSize(columnsCount, columnsWidth, columnHeight); } - private double GetColumnHeight(int columnsCount, Size availableSize) - { - var totalChildrenHeight = Children.Select(c => c.DesiredSize.Height).Sum(); - var availableColumnsHeight = columnsCount * availableSize.Height; - if (totalChildrenHeight <= availableColumnsHeight) - { - // We have enough space for all our items, we try with the available height - return Math.Ceiling(availableSize.Height); - } + private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) + => new Size( + width: (columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * ColumnsSpacing), + height: columnHeight); - // Not enough place for all items. We try with a balanced split. - return Math.Ceiling(totalChildrenHeight / columnsCount); - } + private double GetHeight(int index) => Children[index].DesiredSize.Height; - private struct ColumnData + /// + /// Partition our list into columns. + /// + /// The number of columns. + /// The available height for the columns. + /// + /// An array containing the index of the last item of each column or -1 if the column is not used and + /// the required height for the columns. + /// + private (int[] columnLastIndexes, double columnHeight) Partition(int columnsCount, double availableColumnHeight) { - public int LastChildIndex { get; set; } + var columnLastIndexes = new int[columnsCount]; - public double ColumnHeight { get; set; } - } - - private ColumnData[] DoLayout(int columnsCount, double targetHeight) - { - var columnsData = new ColumnData[columnsCount]; + var totalHeight = Children.Sum(child => child.DesiredSize.Height); + var expectedColumnHeight = Math.Max(availableColumnHeight, totalHeight / columnsCount); - var currentColumnIndex = 0; - var childIndex = 0; - for (; childIndex < Children.Count; childIndex++) - { - columnsData[currentColumnIndex].LastChildIndex = childIndex; - columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; - if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) - { - // We have pass the end, we move to the next column. - columnsData[currentColumnIndex].LastChildIndex = childIndex - 1; // TODO: handle the case of super big items that do not fit. - columnsData[currentColumnIndex].ColumnHeight -= Children[childIndex].DesiredSize.Height; - currentColumnIndex++; + // We ensure that we have enough space to place the first item. + expectedColumnHeight = Math.Max(expectedColumnHeight, GetHeight(0)); - if (currentColumnIndex >= columnsData.Length) - { - // We have filled our last column. We stop - break; - } + var columnIndex = 0; + var hasFoundPartition = DoPartition( + columnLastIndexes, + columnIndex, + childStartIndex: 0, + expectedColumnHeight: expectedColumnHeight); - // We fill the data for our next column - columnsData[currentColumnIndex].LastChildIndex = childIndex; - columnsData[currentColumnIndex].ColumnHeight = Children[childIndex].DesiredSize.Height; - } + // We have some overflow items, we move the first element of column 1 to column 0 and restart the logic. + while (!hasFoundPartition) + { + columnLastIndexes[0]++; + expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height); + + columnIndex = 1; + hasFoundPartition = DoPartition( + columnLastIndexes, + columnIndex, + childStartIndex: columnLastIndexes[0] + 1, + expectedColumnHeight: expectedColumnHeight); } - while (childIndex < Children.Count) - { - // We have remaining items but no more space in our targetHeight height columns. - // We move the first items of each column to the previous one. - columnsData[0].LastChildIndex++; - var nextChildHeight = Children[columnsData[0].LastChildIndex].DesiredSize.Height; - columnsData[0].ColumnHeight += nextChildHeight; + return (columnLastIndexes, expectedColumnHeight); + } - columnsData[1].ColumnHeight -= nextChildHeight; + /// + /// Partition our list in buckets which have all a size lower than . + /// + /// The array containing the indexes of the last item of each column. + /// The index of the first column where to apply the partition logic. + /// The index of the first child to consider. + /// The expected height for our columns. + /// True if we've been able to partition all the children in columns. + private bool DoPartition( + int[] columnLastIndexes, + int columnIndex, + int childStartIndex, + double expectedColumnHeight) + { + var currentColumnHeight = 0.0; + var partitionSucceeded = true; - // We get our new target height - targetHeight = columnsData[0].ColumnHeight; // columnsData.Max(cd => cd.ColumnHeight); we do not pick max to have a better alignment. + for (var i = childStartIndex; i < Children.Count; i++) + { + var currentChildHeight = GetHeight(i); + var columnHeightAfterAdd = currentColumnHeight + currentChildHeight; - // We adjust the other columns so we first reset our data and restart the loop - for (var i = 1; i < columnsCount; i++) + if (columnHeightAfterAdd > expectedColumnHeight) { - columnsData[i].ColumnHeight = 0.0; - columnsData[i].LastChildIndex = 0; - } + if (columnIndex == 0) + { + // Now that we have the items that we want to add in our first column, we adjust expectedColumnHeight + // to be the height of this first column in order to have a more natural layout. + expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height); + } - currentColumnIndex = 1; - childIndex = columnsData[0].LastChildIndex + 1; - for (; childIndex < Children.Count; childIndex++) - { - columnsData[currentColumnIndex].LastChildIndex = childIndex; - columnsData[currentColumnIndex].ColumnHeight += Children[childIndex].DesiredSize.Height; - if (columnsData[currentColumnIndex].ColumnHeight > targetHeight) + columnIndex++; + if (columnIndex < columnLastIndexes.Length) { - // We have pass the end, we move to the next column. - columnsData[currentColumnIndex].LastChildIndex = childIndex - 1; // TODO: handle the case of super big items that do not fit. - columnsData[currentColumnIndex].ColumnHeight -= Children[childIndex].DesiredSize.Height; - currentColumnIndex++; - - if (currentColumnIndex >= columnsData.Length) - { - // We have filled our last column. We stop - break; - } - - // We fill the data for our next column - columnsData[currentColumnIndex].LastChildIndex = childIndex; - columnsData[currentColumnIndex].ColumnHeight = Children[childIndex].DesiredSize.Height; + columnLastIndexes[columnIndex] = i; + currentColumnHeight = currentChildHeight; } + else + { + partitionSucceeded = false; + break; + } + } + else + { + columnLastIndexes[columnIndex] = i; + currentColumnHeight = columnHeightAfterAdd; } } - return columnsData; - } + // We set the indexes of the empty columns to -1 + columnIndex++; + for (; columnIndex < columnLastIndexes.Length; columnIndex++) + { + columnLastIndexes[columnIndex] = -1; + } - private Size GetFinalSize(ColumnData[] columnsData, double columnWidth) - { - var requiredColumnsCount = columnsData.TakeWhile(cd => cd.LastChildIndex > 0).Count(); - var requiredColumnsWidth = requiredColumnsCount * columnWidth; - var requiredSpacingWidth = Math.Max(0, requiredColumnsCount - 1) * ColumnsSpacing; - var maxHeight = columnsData.Max(cd => cd.ColumnHeight); - return new Size( - requiredColumnsWidth + requiredSpacingWidth, - maxHeight); + return partitionSucceeded; } private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) From a6d8db1e3e5fb353abda3b52388230e757899672 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 28 Jun 2020 00:04:03 +0200 Subject: [PATCH 09/26] fix comment --- .../MultiColumnsStackPanel/MultiColumnsStackPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index bde793d597e..bb628b8e901 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -223,7 +223,7 @@ private bool DoPartition( { if (columnIndex == 0) { - // Now that we have the items that we want to add in our first column, we adjust expectedColumnHeight + // Now that we have the items for our first column, we adjust expectedColumnHeight // to be the height of this first column in order to have a more natural layout. expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height); } From bd5a1169ad3dc5ce03e07f4f9b47b0fdf510ac18 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 28 Jun 2020 00:35:22 +0200 Subject: [PATCH 10/26] add items spacing support --- .../MultiColumnsStackPanel.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index bb628b8e901..236efd4a129 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -132,7 +132,7 @@ protected override Size ArrangeOverride(Size finalSize) child.Arrange(rect); - height += child.DesiredSize.Height; + height += child.DesiredSize.Height + ItemsSpacing; if (childIndex == columnLastIndex[currentColumnIndex]) { // We've reached the last item for the current column. We move to the next one. @@ -174,7 +174,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) expectedColumnHeight = Math.Max(expectedColumnHeight, GetHeight(0)); var columnIndex = 0; - var hasFoundPartition = DoPartition( + var (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( columnLastIndexes, columnIndex, childStartIndex: 0, @@ -184,17 +184,17 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) while (!hasFoundPartition) { columnLastIndexes[0]++; - expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height); + expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndexes[0] * ItemsSpacing); columnIndex = 1; - hasFoundPartition = DoPartition( + (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( columnLastIndexes, columnIndex, childStartIndex: columnLastIndexes[0] + 1, expectedColumnHeight: expectedColumnHeight); } - return (columnLastIndexes, expectedColumnHeight); + return (columnLastIndexes, adjustedExpectedColumnHeight); } /// @@ -205,7 +205,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) /// The index of the first child to consider. /// The expected height for our columns. /// True if we've been able to partition all the children in columns. - private bool DoPartition( + private (bool partitionSuceeded, double expectedColumnHeight) DoPartition( int[] columnLastIndexes, int columnIndex, int childStartIndex, @@ -225,7 +225,7 @@ private bool DoPartition( { // Now that we have the items for our first column, we adjust expectedColumnHeight // to be the height of this first column in order to have a more natural layout. - expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height); + expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndexes[0] * ItemsSpacing); } columnIndex++; @@ -243,7 +243,7 @@ private bool DoPartition( else { columnLastIndexes[columnIndex] = i; - currentColumnHeight = columnHeightAfterAdd; + currentColumnHeight = columnHeightAfterAdd + ItemsSpacing; } } @@ -254,7 +254,7 @@ private bool DoPartition( columnLastIndexes[columnIndex] = -1; } - return partitionSucceeded; + return (partitionSucceeded, expectedColumnHeight); } private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) From 809917a3737cdaa808f6d4b813667b8791efc600 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 28 Jun 2020 00:36:21 +0200 Subject: [PATCH 11/26] fix no children case --- .../MultiColumnsStackPanel/MultiColumnsStackPanel.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 236efd4a129..1766b279e0f 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -171,7 +171,10 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) var expectedColumnHeight = Math.Max(availableColumnHeight, totalHeight / columnsCount); // We ensure that we have enough space to place the first item. - expectedColumnHeight = Math.Max(expectedColumnHeight, GetHeight(0)); + if (Children.Count > 0) + { + expectedColumnHeight = Math.Max(expectedColumnHeight, GetHeight(0)); + } var columnIndex = 0; var (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( From 8dd4efa529b7ccf04d00a069b3a7de9d79ad7728 Mon Sep 17 00:00:00 2001 From: Vincent Date: Thu, 2 Jul 2020 23:07:18 +0200 Subject: [PATCH 12/26] fix algorithm --- .../MultiColumnsStackPanel.cs | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 1766b279e0f..01b5ad44c96 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -122,26 +122,26 @@ protected override Size ArrangeOverride(Size finalSize) var (columnLastIndex, columnHeight) = Partition(columnsCount, finalSize.Height); var rect = new Rect(0, 0, columnsWidth, 0); - var height = 0.0; var currentColumnIndex = 0; for (var childIndex = 0; childIndex < Children.Count; childIndex++) { var child = Children[childIndex]; - rect.Y = height; rect.Height = child.DesiredSize.Height; child.Arrange(rect); - height += child.DesiredSize.Height + ItemsSpacing; if (childIndex == columnLastIndex[currentColumnIndex]) { // We've reached the last item for the current column. We move to the next one. - height = 0.0; currentColumnIndex++; rect.X += columnsWidth + ColumnsSpacing; rect.Y = 0; } + else + { + rect.Y += child.DesiredSize.Height + ItemsSpacing; + } } return GetSize(columnsCount, columnsWidth, columnHeight); @@ -168,7 +168,11 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) var columnLastIndexes = new int[columnsCount]; var totalHeight = Children.Sum(child => child.DesiredSize.Height); - var expectedColumnHeight = Math.Max(availableColumnHeight, totalHeight / columnsCount); + var expectedColumnHeight = totalHeight / columnsCount; + if (!double.IsInfinity(availableColumnHeight)) + { + expectedColumnHeight = Math.Max(availableColumnHeight, expectedColumnHeight); + } // We ensure that we have enough space to place the first item. if (Children.Count > 0) @@ -187,7 +191,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) while (!hasFoundPartition) { columnLastIndexes[0]++; - expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndexes[0] * ItemsSpacing); + expectedColumnHeight = GetColumnHeight(columnLastIndexes[0]); columnIndex = 1; (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( @@ -228,14 +232,14 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) { // Now that we have the items for our first column, we adjust expectedColumnHeight // to be the height of this first column in order to have a more natural layout. - expectedColumnHeight = Children.Take(columnLastIndexes[0] + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndexes[0] * ItemsSpacing); + expectedColumnHeight = currentColumnHeight - ItemsSpacing; } columnIndex++; if (columnIndex < columnLastIndexes.Length) { columnLastIndexes[columnIndex] = i; - currentColumnHeight = currentChildHeight; + currentColumnHeight = currentChildHeight + ItemsSpacing; } else { @@ -272,5 +276,8 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) return (columnsCount, columnsWidth); } + + private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * ItemsSpacing); + } } From f6a938462af1161f147bf99f5467fb257a33664e Mon Sep 17 00:00:00 2001 From: Vincent Date: Thu, 2 Jul 2020 23:35:52 +0200 Subject: [PATCH 13/26] add scroll viewer viewport support --- .../MultiColumnsStackPanel/MultiColumnsStackPanel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 01b5ad44c96..6365ff605cf 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -174,6 +174,12 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) expectedColumnHeight = Math.Max(availableColumnHeight, expectedColumnHeight); } + // If we are wrapped in a scroll viewer, we get the size of the scroll viewer to fill as much as possible the columns + if (Parent is ScrollViewer scrollviewer) + { + expectedColumnHeight = Math.Max(expectedColumnHeight, scrollviewer.ViewportHeight); + } + // We ensure that we have enough space to place the first item. if (Children.Count > 0) { From 340b29e19ad4c17c314be488a5c4802076178983 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 4 Jul 2020 22:16:20 +0200 Subject: [PATCH 14/26] update sample code --- .../MultiColumnsStackPanelCode.bind | 87 +++++++++++-------- .../MultiColumnsStackPanelPage.xaml | 86 ++++++++++-------- 2 files changed, 103 insertions(+), 70 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index 45c93013713..10aec051f55 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -7,40 +7,57 @@ mc:Ignorable="d"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index 35b8d8a1ac2..739c1b0cd18 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -8,40 +8,56 @@ mc:Ignorable="d"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 29aa3e4b90bcc9a6fbc52484e6e0796618c4b5ca Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 5 Jul 2020 00:08:16 +0200 Subject: [PATCH 15/26] fix pixel rounding issue --- .../MultiColumnsStackPanelCode.bind | 1 + .../MultiColumnsStackPanelPage.xaml | 1 + .../MultiColumnsStackPanel.cs | 41 ++++++++++++------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index 10aec051f55..e529e55336a 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -57,6 +57,7 @@ + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index 739c1b0cd18..e613824d31a 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -57,6 +57,7 @@ + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 6365ff605cf..68869daa058 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -130,7 +130,7 @@ protected override Size ArrangeOverride(Size finalSize) child.Arrange(rect); - if (childIndex == columnLastIndex[currentColumnIndex]) + if (currentColumnIndex < columnLastIndex.Length && childIndex == columnLastIndex[currentColumnIndex]) { // We've reached the last item for the current column. We move to the next one. currentColumnIndex++; @@ -148,9 +148,19 @@ protected override Size ArrangeOverride(Size finalSize) } private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) - => new Size( - width: (columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * ColumnsSpacing), + { + // We use this trick to fix rounding errors when scaling is greater than 100% + // The value we return from MeasureOverride() if converted using floor((value * scalefactor) + .5)/scalefactor before being provided to ArrangeOverride() and in some + // cases, we are receiving a value lower than what we're expecting. For example, when we return a desired width of 707 px, we receive 706,8571 in arrange and we're dropping + // one column. Forcing even numbers is an easy way to limit the issue. + // See: https://github.com/microsoft/microsoft-ui-xaml/issues/1441 + var requiredColumnWidth = Math.Ceiling((columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * ColumnsSpacing)); + var evenColumnWidth = requiredColumnWidth % 2 == 0 ? requiredColumnWidth : (requiredColumnWidth + 1); + + return new Size( + width: evenColumnWidth, height: columnHeight); + } private double GetHeight(int index) => Children[index].DesiredSize.Height; @@ -167,7 +177,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) { var columnLastIndexes = new int[columnsCount]; - var totalHeight = Children.Sum(child => child.DesiredSize.Height); + var totalHeight = Children.Sum(child => child.DesiredSize.Height) + (Math.Max(Children.Count - 1, 0) * ItemsSpacing); var expectedColumnHeight = totalHeight / columnsCount; if (!double.IsInfinity(availableColumnHeight)) { @@ -194,17 +204,20 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) expectedColumnHeight: expectedColumnHeight); // We have some overflow items, we move the first element of column 1 to column 0 and restart the logic. - while (!hasFoundPartition) + if (columnLastIndexes.Length > 1) { - columnLastIndexes[0]++; - expectedColumnHeight = GetColumnHeight(columnLastIndexes[0]); - - columnIndex = 1; - (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( - columnLastIndexes, - columnIndex, - childStartIndex: columnLastIndexes[0] + 1, - expectedColumnHeight: expectedColumnHeight); + while (!hasFoundPartition) + { + columnLastIndexes[0]++; + expectedColumnHeight = GetColumnHeight(columnLastIndexes[0]); + + columnIndex = 1; + (hasFoundPartition, adjustedExpectedColumnHeight) = DoPartition( + columnLastIndexes, + columnIndex, + childStartIndex: columnLastIndexes[0] + 1, + expectedColumnHeight: expectedColumnHeight); + } } return (columnLastIndexes, adjustedExpectedColumnHeight); From 6d39cbf0aed301971610e6f420da418087ca8af1 Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 6 Jul 2020 08:27:21 +0200 Subject: [PATCH 16/26] add horizontal alignment support --- .../MultiColumnsStackPanel.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 68869daa058..9d7a5369617 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -128,7 +128,7 @@ protected override Size ArrangeOverride(Size finalSize) var child = Children[childIndex]; rect.Height = child.DesiredSize.Height; - child.Arrange(rect); + ArrangeChild(child, rect); if (currentColumnIndex < columnLastIndex.Length && childIndex == columnLastIndex[currentColumnIndex]) { @@ -147,6 +147,42 @@ protected override Size ArrangeOverride(Size finalSize) return GetSize(columnsCount, columnsWidth, columnHeight); } + private void ArrangeChild(UIElement element, Rect position) + { + var requestedAlignement = HorizontalContentAlignment; + if (element is Control control) + { + // We use the control defined value + requestedAlignement = control.HorizontalAlignment; + } + + if (element.DesiredSize.Width >= position.Width) + { + requestedAlignement = HorizontalAlignment.Stretch; + } + + switch (requestedAlignement) + { + case HorizontalAlignment.Left: + position.Width = element.DesiredSize.Width; + break; + case HorizontalAlignment.Center: + position.X = (position.Width - element.DesiredSize.Width) / 2.0; + position.Width = element.DesiredSize.Width; + break; + case HorizontalAlignment.Right: + position.X = position.Width - element.DesiredSize.Width; + position.Width = element.DesiredSize.Width; + break; + case HorizontalAlignment.Stretch: + default: + // no adjustment needed, we use the received value. + break; + } + + element.Arrange(position); + } + private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) { // We use this trick to fix rounding errors when scaling is greater than 100% From e993503cc9d68b598ac1f26e4856275fb0e7ecb1 Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 7 Jul 2020 22:53:44 +0200 Subject: [PATCH 17/26] update configuration --- Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index b65a967d288..5f6834b6333 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -235,11 +235,11 @@ "Name": "MultiColumnsStackPanel", "Type": "MultiColumnsStackPanelPage", "Subcategory": "Layout", - "About": "The MultiColumnsStackPanel Control positions child elements .", - "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel", + "About": "The MultiColumnsStackPanel Control positions child elements in fixed size columns.", + "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel", "XamlCodeFile": "MultiColumnsStackPanelCode.bind", "Icon": "/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanel.png", - "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/WrapPanel.md" + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/MultiColumnsStackPanel.md" }, { "Name": "WrapLayout", From 8f6539f69130c2ddadaf8e5eb1b5225ffb3ac73e Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 7 Jul 2020 23:00:15 +0200 Subject: [PATCH 18/26] update comments --- .../MultiColumnsStackPanel/MultiColumnsStackPanel.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 9d7a5369617..c9ec716b6f9 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -206,8 +206,9 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) /// The number of columns. /// The available height for the columns. /// - /// An array containing the index of the last item of each column or -1 if the column is not used and + /// - columnLastIndexes: An array containing the index of the last item of each column or -1 if the column is not used and /// the required height for the columns. + /// - columnHeight: the height required to draw our columns. /// private (int[] columnLastIndexes, double columnHeight) Partition(int columnsCount, double availableColumnHeight) { @@ -266,7 +267,10 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) /// The index of the first column where to apply the partition logic. /// The index of the first child to consider. /// The expected height for our columns. - /// True if we've been able to partition all the children in columns. + /// + /// - partitionSuceeded: true if we've been able to partition all the children in columns. + /// - expectedColumnHeight: the adjusted height of the first column (fitting exactly all the first column items). + /// private (bool partitionSuceeded, double expectedColumnHeight) DoPartition( int[] columnLastIndexes, int columnIndex, From c48c746b1708cbba505decedde20aaa5ab5b515f Mon Sep 17 00:00:00 2001 From: Vincent Date: Thu, 23 Jul 2020 22:23:33 +0200 Subject: [PATCH 19/26] renamed dependency properties --- .../MultiColumnsStackPanelCode.bind | 4 +- .../MultiColumnsStackPanelPage.xaml | 4 +- .../MultiColumnsStackPanel.cs | 42 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index e529e55336a..4b233c62697 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -14,8 +14,8 @@ diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml index e613824d31a..3e460249040 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelPage.xaml @@ -14,8 +14,8 @@ VerticalScrollMode="Auto"> diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index c9ec716b6f9..fd135c03801 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -25,19 +25,19 @@ public class MultiColumnsStackPanel : Panel new PropertyMetadata(0.0, OnLayoutPropertyChanged)); /// - /// The DP to store the ColumnsSpacing value. + /// The DP to store the HorizontalSpacing value. /// - public static readonly DependencyProperty ColumnsSpacingProperty = DependencyProperty.Register( - nameof(ColumnsSpacing), + public static readonly DependencyProperty HorizontalSpacingProperty = DependencyProperty.Register( + nameof(HorizontalSpacing), typeof(double), typeof(MultiColumnsStackPanel), new PropertyMetadata(0.0, OnLayoutPropertyChanged)); /// - /// The DP to store the ItemsSpacing value. + /// The DP to store the VerticalSpacing value. /// - public static readonly DependencyProperty ItemsSpacingProperty = DependencyProperty.Register( - nameof(ItemsSpacing), + public static readonly DependencyProperty VerticalSpacingProperty = DependencyProperty.Register( + nameof(VerticalSpacing), typeof(double), typeof(MultiColumnsStackPanel), new PropertyMetadata(0.0, OnLayoutPropertyChanged)); @@ -64,19 +64,19 @@ public double MaxColumnWidth /// /// Gets or sets the spacing between two columns. /// - public double ColumnsSpacing + public double HorizontalSpacing { - get => (double)GetValue(ColumnsSpacingProperty); - set => SetValue(ColumnsSpacingProperty, value); + get => (double)GetValue(HorizontalSpacingProperty); + set => SetValue(HorizontalSpacingProperty, value); } /// /// Gets or sets the spacing between two items. /// - public double ItemsSpacing + public double VerticalSpacing { - get => (double)GetValue(ItemsSpacingProperty); - set => SetValue(ItemsSpacingProperty, value); + get => (double)GetValue(VerticalSpacingProperty); + set => SetValue(VerticalSpacingProperty, value); } /// @@ -135,12 +135,12 @@ protected override Size ArrangeOverride(Size finalSize) // We've reached the last item for the current column. We move to the next one. currentColumnIndex++; - rect.X += columnsWidth + ColumnsSpacing; + rect.X += columnsWidth + HorizontalSpacing; rect.Y = 0; } else { - rect.Y += child.DesiredSize.Height + ItemsSpacing; + rect.Y += child.DesiredSize.Height + VerticalSpacing; } } @@ -190,7 +190,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) // cases, we are receiving a value lower than what we're expecting. For example, when we return a desired width of 707 px, we receive 706,8571 in arrange and we're dropping // one column. Forcing even numbers is an easy way to limit the issue. // See: https://github.com/microsoft/microsoft-ui-xaml/issues/1441 - var requiredColumnWidth = Math.Ceiling((columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * ColumnsSpacing)); + var requiredColumnWidth = Math.Ceiling((columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * HorizontalSpacing)); var evenColumnWidth = requiredColumnWidth % 2 == 0 ? requiredColumnWidth : (requiredColumnWidth + 1); return new Size( @@ -214,7 +214,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) { var columnLastIndexes = new int[columnsCount]; - var totalHeight = Children.Sum(child => child.DesiredSize.Height) + (Math.Max(Children.Count - 1, 0) * ItemsSpacing); + var totalHeight = Children.Sum(child => child.DesiredSize.Height) + (Math.Max(Children.Count - 1, 0) * VerticalSpacing); var expectedColumnHeight = totalHeight / columnsCount; if (!double.IsInfinity(availableColumnHeight)) { @@ -291,14 +291,14 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) { // Now that we have the items for our first column, we adjust expectedColumnHeight // to be the height of this first column in order to have a more natural layout. - expectedColumnHeight = currentColumnHeight - ItemsSpacing; + expectedColumnHeight = currentColumnHeight - VerticalSpacing; } columnIndex++; if (columnIndex < columnLastIndexes.Length) { columnLastIndexes[columnIndex] = i; - currentColumnHeight = currentChildHeight + ItemsSpacing; + currentColumnHeight = currentChildHeight + VerticalSpacing; } else { @@ -309,7 +309,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) else { columnLastIndexes[columnIndex] = i; - currentColumnHeight = columnHeightAfterAdd + ItemsSpacing; + currentColumnHeight = columnHeightAfterAdd + VerticalSpacing; } } @@ -329,14 +329,14 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) var columnsCount = 1; if (columnsWidth < availableSize.Width) { - var additionalColumns = (int)((availableSize.Width - columnsWidth) / (columnsWidth + ColumnsSpacing)); + var additionalColumns = (int)((availableSize.Width - columnsWidth) / (columnsWidth + HorizontalSpacing)); columnsCount += additionalColumns; } return (columnsCount, columnsWidth); } - private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * ItemsSpacing); + private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * VerticalSpacing); } } From 848288a8506fd2ea28218ba488fde0b0152767c3 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 29 Jul 2020 22:44:21 +0200 Subject: [PATCH 20/26] add horizontal padding support --- .../MultiColumnsStackPanelCode.bind | 3 +- .../MultiColumnsStackPanelPage.xaml | 7 +++-- .../MultiColumnsStackPanel.cs | 30 +++++++++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index 4b233c62697..bf17722ec3a 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -16,7 +16,8 @@ HorizontalContentAlignment="@[HorizontalContentAlignment:Enum:HorizontalAlignment.Stretch]" HorizontalSpacing="@[HorizontalSpacing:Slider:12:0-120]" VerticalSpacing="@[VerticalSpacing:Slider:8:0-64]" - MaxColumnWidth="@[MaxColumnWidth:Slider:240:0-500]"> + MaxColumnWidth="@[MaxColumnWidth:Slider:240:0-500]" + Padding="@[Padding:Thickness:0,0,0,0]@"> - + MaxColumnWidth="240" + VerticalSpacing="24"> + /// The DP to store the Padding value. + /// + public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register( + nameof(Padding), + typeof(Thickness), + typeof(MultiColumnsStackPanel), + new PropertyMetadata(new Thickness(0), OnLayoutPropertyChanged)); + + /// + /// Gets or sets the padding inside the control. + /// + public Thickness Padding + { + get => (Thickness)GetValue(PaddingProperty); + set => SetValue(PaddingProperty, value); + } + /// /// Gets or sets the maximum width for the columns. /// If the value is 0, it will display a single column (like a vertical ). @@ -121,7 +140,7 @@ protected override Size ArrangeOverride(Size finalSize) // We split the items across all the columns var (columnLastIndex, columnHeight) = Partition(columnsCount, finalSize.Height); - var rect = new Rect(0, 0, columnsWidth, 0); + var rect = new Rect(Padding.Left, 0, columnsWidth, 0); var currentColumnIndex = 0; for (var childIndex = 0; childIndex < Children.Count; childIndex++) { @@ -190,7 +209,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) // cases, we are receiving a value lower than what we're expecting. For example, when we return a desired width of 707 px, we receive 706,8571 in arrange and we're dropping // one column. Forcing even numbers is an easy way to limit the issue. // See: https://github.com/microsoft/microsoft-ui-xaml/issues/1441 - var requiredColumnWidth = Math.Ceiling((columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * HorizontalSpacing)); + var requiredColumnWidth = Math.Ceiling((columnsCount * columnsWidth) + (Math.Max(0, columnsCount - 1) * HorizontalSpacing) + Padding.Left + Padding.Right); var evenColumnWidth = requiredColumnWidth % 2 == 0 ? requiredColumnWidth : (requiredColumnWidth + 1); return new Size( @@ -325,11 +344,12 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) private (int columnsCount, double columnsWidth) GetAvailableColumnsInformation(Size availableSize) { - var columnsWidth = MaxColumnWidth > 0 ? Math.Min(MaxColumnWidth, availableSize.Width) : availableSize.Width; + var availableWidth = Math.Max(availableSize.Width - Padding.Left - Padding.Right, 0); + var columnsWidth = MaxColumnWidth > 0 ? Math.Min(MaxColumnWidth, availableWidth) : availableWidth; var columnsCount = 1; - if (columnsWidth < availableSize.Width) + if (columnsWidth < availableWidth) { - var additionalColumns = (int)((availableSize.Width - columnsWidth) / (columnsWidth + HorizontalSpacing)); + var additionalColumns = (int)((availableWidth - columnsWidth) / (columnsWidth + HorizontalSpacing)); columnsCount += additionalColumns; } From 0ef895a9647a9efed187444c8260f9a4717ee410 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 29 Jul 2020 23:02:42 +0200 Subject: [PATCH 21/26] add vertical padding support --- .../MultiColumnsStackPanel.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index d285ec3e129..35c81ee5d80 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -140,7 +140,7 @@ protected override Size ArrangeOverride(Size finalSize) // We split the items across all the columns var (columnLastIndex, columnHeight) = Partition(columnsCount, finalSize.Height); - var rect = new Rect(Padding.Left, 0, columnsWidth, 0); + var rect = new Rect(Padding.Left, Padding.Top, columnsWidth, 0); var currentColumnIndex = 0; for (var childIndex = 0; childIndex < Children.Count; childIndex++) { @@ -155,7 +155,7 @@ protected override Size ArrangeOverride(Size finalSize) currentColumnIndex++; rect.X += columnsWidth + HorizontalSpacing; - rect.Y = 0; + rect.Y = Padding.Top; } else { @@ -217,7 +217,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) height: columnHeight); } - private double GetHeight(int index) => Children[index].DesiredSize.Height; + private double GetChildrenHeight(int index) => Children[index].DesiredSize.Height; /// /// Partition our list into columns. @@ -231,6 +231,8 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) /// private (int[] columnLastIndexes, double columnHeight) Partition(int columnsCount, double availableColumnHeight) { + availableColumnHeight = availableColumnHeight - Padding.Top - Padding.Bottom; + var columnLastIndexes = new int[columnsCount]; var totalHeight = Children.Sum(child => child.DesiredSize.Height) + (Math.Max(Children.Count - 1, 0) * VerticalSpacing); @@ -249,7 +251,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) // We ensure that we have enough space to place the first item. if (Children.Count > 0) { - expectedColumnHeight = Math.Max(expectedColumnHeight, GetHeight(0)); + expectedColumnHeight = Math.Max(expectedColumnHeight, GetChildrenHeight(0)); } var columnIndex = 0; @@ -296,12 +298,12 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) int childStartIndex, double expectedColumnHeight) { - var currentColumnHeight = 0.0; + var currentColumnHeight = Padding.Top + Padding.Bottom; var partitionSucceeded = true; for (var i = childStartIndex; i < Children.Count; i++) { - var currentChildHeight = GetHeight(i); + var currentChildHeight = GetChildrenHeight(i); var columnHeightAfterAdd = currentColumnHeight + currentChildHeight; if (columnHeightAfterAdd > expectedColumnHeight) @@ -317,7 +319,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) if (columnIndex < columnLastIndexes.Length) { columnLastIndexes[columnIndex] = i; - currentColumnHeight = currentChildHeight + VerticalSpacing; + currentColumnHeight = Padding.Top + Padding.Bottom + currentChildHeight + VerticalSpacing; } else { @@ -356,7 +358,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) return (columnsCount, columnsWidth); } - private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * VerticalSpacing); + private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * VerticalSpacing) + Padding.Top + Padding.Bottom; } } From 8856498540db09a749401821eabf17d701ae1e9d Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 9 Nov 2020 22:09:31 +0100 Subject: [PATCH 22/26] fix stylecop issues --- .../MultiColumnsStackPanel/MultiColumnsStackPanel.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs index 35c81ee5d80..2cbde545fa5 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MultiColumnsStackPanel/MultiColumnsStackPanel.cs @@ -51,7 +51,6 @@ public class MultiColumnsStackPanel : Panel typeof(MultiColumnsStackPanel), new PropertyMetadata(HorizontalAlignment.Stretch, OnLayoutPropertyChanged)); - /// /// The DP to store the Padding value. /// @@ -358,7 +357,7 @@ private Size GetSize(int columnsCount, double columnsWidth, double columnHeight) return (columnsCount, columnsWidth); } - private double GetColumnHeight(int columnLastIndex) => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * VerticalSpacing) + Padding.Top + Padding.Bottom; - + private double GetColumnHeight(int columnLastIndex) + => Children.Take(columnLastIndex + 1).Sum(child => child.DesiredSize.Height) + (columnLastIndex * VerticalSpacing) + Padding.Top + Padding.Bottom; } } From 05d3b08a6f4fa33ac00b12e199ea43f0ed3bab0d Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 9 Nov 2020 22:21:22 +0100 Subject: [PATCH 23/26] Remove HorizontalContentAlignment property --- .../MultiColumnsStackPanelCode.bind | 5 +- .../MultiColumnsStackPanel.cs | 56 +------------------ 2 files changed, 4 insertions(+), 57 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind index bf17722ec3a..c2d0bcce8c1 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MultiColumnsStackPanel/MultiColumnsStackPanelCode.bind @@ -13,13 +13,14 @@ VerticalScrollMode="Auto"> - + +