瀏覽代碼

[Issue 18806] Prevent children of UniformGrid from having negative dimensions when row/col spacing exceeds available space (#18832)

* Add UniformGrid test cases for scenarios where row/column spacing takes more than available space

* Constrain child size to non-negative when performing arrange in UniformGrid
H0tCh0colat3 5 月之前
父節點
當前提交
d8f590d42e

+ 2 - 2
src/Avalonia.Controls/Primitives/UniformGrid.cs

@@ -133,8 +133,8 @@ namespace Avalonia.Controls.Primitives
             var columnSpacing = ColumnSpacing;
             var rowSpacing = RowSpacing;
 
-            var width = (finalSize.Width - (_columns - 1) * columnSpacing) / _columns;
-            var height = (finalSize.Height - (_rows - 1) * rowSpacing) / _rows;
+            var width = Math.Max((finalSize.Width - (_columns - 1) * columnSpacing) / _columns, 0);
+            var height = Math.Max((finalSize.Height - (_rows - 1) * rowSpacing) / _rows, 0);
 
             foreach (var child in Children)
             {

+ 72 - 1
tests/Avalonia.Controls.UnitTests/Primitives/UniformGridTests.cs

@@ -1,4 +1,5 @@
-using Avalonia.Controls.Primitives;
+using System;
+using Avalonia.Controls.Primitives;
 using Avalonia.UnitTests;
 using Xunit;
 
@@ -305,5 +306,75 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(0, desiredSize.Height);
         
         }
+
+        [Fact]
+        public void Arrange_Does_Not_Throw_InvalidOperationException_When_Row_Spacing_Takes_All_Available_Height()
+        {
+            // Minimum required height = 20 (2 row gaps size 10)
+            // Provide height of 19 so that row gaps take all available space
+            // thus, available height for children may be negative.
+            // In that case, UniformGrid should arrange its children with rects of height 0.
+            var target = new UniformGrid
+            {
+                Columns = 1,
+                RowSpacing = 10,
+                Children =
+                {
+                    new Border(),
+                    new Border(),
+                    new Border()
+                }
+            };
+
+            var availableSize = new Size(100, 19);
+
+            target.Measure(Size.Infinity);
+
+            // Fail case:
+            // Invalid operation will be thrown if any child rect contains a negative dimension
+            try
+            {
+                target.Arrange(new Rect(availableSize));
+            }
+            catch (InvalidOperationException exception)
+            {
+                Assert.Fail("Arrange threw InvalidOperationException: " + exception.Message);
+            }
+        }
+
+        [Fact]
+        public void Arrange_Does_Not_Throw_InvalidOperationException_When_Column_Spacing_Takes_All_Available_Width()
+        {
+            // Minimum required width = 20 (2 row gaps size 10)
+            // Provide width of 19 so that column gaps take all available space
+            // thus, available width for children may be negative.
+            // In that case, UniformGrid should arrange its children with rects of width 0.
+            var target = new UniformGrid
+            {
+                Rows = 1,
+                ColumnSpacing = 10,
+                Children =
+                {
+                    new Border(),
+                    new Border(),
+                    new Border()
+                }
+            };
+
+            var availableSize = new Size(19, 100);
+
+            target.Measure(Size.Infinity);
+
+            // Fail case:
+            // Invalid operation will be thrown if any child rect contains a negative dimension
+            try
+            {
+                target.Arrange(new Rect(availableSize));
+            }
+            catch (InvalidOperationException exception)
+            {
+                Assert.Fail("Arrange threw InvalidOperationException: " + exception.Message);
+            }
+        }
     }
 }