diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index a72b5367b6..ed484ec378 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -211,10 +211,8 @@ namespace Avalonia.Controls { var (column, columnSpan) = safeColumns[child]; var (row, rowSpan) = safeRows[child]; - var width = Enumerable.Range(column, columnSpan) - .Select(x => columnResult.LengthList[x].Length.Value).Sum(); - var height = Enumerable.Range(row, rowSpan) - .Select(x => rowResult.LengthList[x].Length.Value).Sum(); + var width = Enumerable.Range(column, columnSpan).Select(x => columnResult.LengthList[x]).Sum(); + var height = Enumerable.Range(row, rowSpan).Select(x => rowResult.LengthList[x]).Sum(); MeasureOnce(child, new Size(width, height)); } @@ -256,10 +254,8 @@ namespace Avalonia.Controls { var (column, columnSpan) = safeColumns[child]; var (row, rowSpan) = safeRows[child]; - var width = Enumerable.Range(column, columnSpan) - .Select(x => columnResult.LengthList[x].Length.Value).Sum(); - var height = Enumerable.Range(row, rowSpan) - .Select(x => rowResult.LengthList[x].Length.Value).Sum(); + var width = Enumerable.Range(column, columnSpan).Select(x => columnResult.LengthList[x]).Sum(); + var height = Enumerable.Range(row, rowSpan).Select(x => rowResult.LengthList[x]).Sum(); child.Arrange(new Rect(0, 0, width, height)); } diff --git a/src/Avalonia.Controls/Utils/GridLayout.cs b/src/Avalonia.Controls/Utils/GridLayout.cs index a872c01695..e77d8d8d88 100644 --- a/src/Avalonia.Controls/Utils/GridLayout.cs +++ b/src/Avalonia.Controls/Utils/GridLayout.cs @@ -176,9 +176,11 @@ namespace Avalonia.Controls.Utils // M6/6. Expand all the left stars. These stars have no conventions or only have max value so they can be expanded from zero to constrant. var dynamicConvention = ExpandStars(conventions, containerLength); + Clip(dynamicConvention, containerLength); - // Stores the measure result. - return new MeasureResult(containerLength, desiredLength, greedyDesiredLength, conventions, dynamicConvention); + // Stores the measuring result. + return new MeasureResult(containerLength, desiredLength, greedyDesiredLength, + conventions, dynamicConvention); } public ArrangeResult Arrange(double finalLength, MeasureResult measure) @@ -201,7 +203,7 @@ namespace Avalonia.Controls.Utils } [Pure] - private static List ExpandStars(IEnumerable conventions, double constraint) + private static List ExpandStars(IEnumerable conventions, double constraint) { // Initial. var dynamicConvention = conventions.Select(x => x.Clone()).ToList(); @@ -244,7 +246,25 @@ namespace Avalonia.Controls.Utils Debug.Assert(dynamicConvention.All(x => x.Length.IsAbsolute)); - return dynamicConvention; + return dynamicConvention.Select(x => x.Length.Value).ToList(); + } + + private static void Clip(IList lengthList, double constraint) + { + var measureLength = 0.0; + for (var i = 0; i < lengthList.Count; i++) + { + var length = lengthList[i]; + if (constraint - measureLength > length) + { + measureLength += length; + } + else + { + lengthList[i] = constraint - measureLength; + measureLength = constraint; + } + } } internal class LengthConvention : ICloneable @@ -299,13 +319,13 @@ namespace Avalonia.Controls.Utils internal class MeasureResult { internal MeasureResult(double containerLength, double desiredLength, double greedyDesiredLength, - IReadOnlyList leanConventions, IReadOnlyList expandedConventions) + IReadOnlyList leanConventions, IReadOnlyList expandedConventions) { ContainerLength = containerLength; DesiredLength = desiredLength; GreedyDesiredLength = greedyDesiredLength; LeanLengthList = leanConventions; - LengthList = expandedConventions.Select(x => x.Length.Value).ToList(); + LengthList = expandedConventions; } public double ContainerLength { get; } diff --git a/tests/Avalonia.Controls.UnitTests/GridLayoutTests.cs b/tests/Avalonia.Controls.UnitTests/GridLayoutTests.cs index 4ffdd24894..c28b5f044d 100644 --- a/tests/Avalonia.Controls.UnitTests/GridLayoutTests.cs +++ b/tests/Avalonia.Controls.UnitTests/GridLayoutTests.cs @@ -9,6 +9,8 @@ namespace Avalonia.Controls.UnitTests { [Theory] [InlineData("100, 200, 300", 800d, 600d, new[] { 100d, 200d, 300d })] + [InlineData("100, 200, 300", 600d, 600d, new[] { 100d, 200d, 300d })] + [InlineData("100, 200, 300", 400d, 400d, new[] { 100d, 200d, 100d })] public void MeasureArrange_AllPixelLength_Correct(string length, double containerLength, double expectedDesiredLength, IList expectedLengthList) { @@ -55,19 +57,6 @@ namespace Avalonia.Controls.UnitTests TestRowDefinitionsOnly(length, containerLength, expectedDesiredLength, expectedLengthList); } - [Fact] - public void MeasureArrange_AllPixelLengthButNotEnough_Correct() - { - // Arrange - var layout = new GridLayout(new RowDefinitions("100,200,300")); - - // Measure - Action & Assert - var measure = layout.Measure(400); - Assert.Equal(new[] { 100d, 200d, 300d }, measure.LengthList); - - // Arrange - Action & Assert - } - [SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local")] private static void TestRowDefinitionsOnly(string length, double containerLength, double expectedDesiredLength, IList expectedLengthList)