Bläddra i källkod

Merge pull request #8727 from byme8/fix/relative-layout-crash-with-infinite-size

Fix RelativePanel crash inside StackPanel
Max Katz 3 år sedan
förälder
incheckning
f9faa6a2f3

+ 17 - 8
src/Avalonia.Controls/RelativePanel.cs

@@ -36,7 +36,10 @@ namespace Avalonia.Controls
             foreach (Layoutable child in Children)
             {
                 if (child == null)
+                {
                     continue;
+                }
+
                 var node = _childGraph.AddNode(child);
 
                 node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child));
@@ -51,17 +54,18 @@ namespace Avalonia.Controls
 
                 node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignHorizontalCenterWithProperty, child));
                 node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignVerticalCenterWithProperty, child));
-
             }
+
             _childGraph.Measure(availableSize);
 
             _childGraph.Reset(false);
-            var calcWidth = Width.IsNaN() && HorizontalAlignment != HorizontalAlignment.Stretch;
-            var calcHeight = Height.IsNaN() && VerticalAlignment != VerticalAlignment.Stretch;
+            var calcWidth = Width.IsNaN() && (HorizontalAlignment != HorizontalAlignment.Stretch);
+            var calcHeight = Height.IsNaN() && (VerticalAlignment != VerticalAlignment.Stretch);
 
             var boundingSize = _childGraph.GetBoundingSize(calcWidth, calcHeight);
             _childGraph.Reset();
             _childGraph.Measure(boundingSize);
+            
             return boundingSize;
         }
 
@@ -171,6 +175,7 @@ namespace Avalonia.Controls
                                 prevSize = prevSize.WithWidth(prevSize.Width + prevNode.OriginDesiredSize.Width);
                                 prevNode.HorizontalOffsetFlag = true;
                             }
+
                             if (node.VerticalOffsetFlag)
                             {
                                 prevNode.VerticalOffsetFlag = true;
@@ -186,6 +191,7 @@ namespace Avalonia.Controls
                                 prevSize = prevSize.WithHeight(prevSize.Height + node.OriginDesiredSize.Height);
                                 prevNode.VerticalOffsetFlag = true;
                             }
+
                             if (node.HorizontalOffsetFlag)
                             {
                                 prevNode.HorizontalOffsetFlag = true;
@@ -269,16 +275,16 @@ namespace Avalonia.Controls
                         MeasureChild(node);
                         continue;
                     }
-                    
+
                     if (node.OutgoingNodes.All(item => item.Measured))
                     {
                         MeasureChild(node);
                         continue;
                     }
-                    
+
                     if (!set.Add(node.Element))
                         throw new Exception("RelativePanel error: Circular dependency detected. Layout could not complete.");
-                    
+
                     Measure(node.OutgoingNodes, set);
 
                     if (!node.Measured)
@@ -507,8 +513,11 @@ namespace Avalonia.Controls
                     boundingSize = boundingSize.WithHeight(Math.Max(boundingSize.Height, size.Height));
                 }
 
-                boundingSize = boundingSize.WithWidth(calcWidth ? boundingSize.Width : AvailableSize.Width);
-                boundingSize = boundingSize.WithHeight(calcHeight ? boundingSize.Height : AvailableSize.Height);
+                var availableWidth = double.IsInfinity(AvailableSize.Width) ? boundingSize.Width : AvailableSize.Width;
+                var availableHeight = double.IsInfinity(AvailableSize.Height) ? boundingSize.Height : AvailableSize.Height;
+
+                boundingSize = boundingSize.WithWidth(calcWidth ? boundingSize.Width : availableWidth);
+                boundingSize = boundingSize.WithHeight(calcHeight ? boundingSize.Height : availableHeight);
                 return boundingSize;
             }
         }

+ 29 - 0
tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs

@@ -138,5 +138,34 @@ namespace Avalonia.Controls.UnitTests
             Assert.Equal(new Rect(0, 0, 20, 20), target.Children[0].Bounds);
             Assert.Equal(new Rect(0, -20, 20, 20), target.Children[1].Bounds);
         }
+
+        [Theory]
+        [InlineData(100, 100, 100, 100)]
+        [InlineData(100, double.PositiveInfinity, 100, 40)]
+        [InlineData(double.PositiveInfinity, 100, 20, 100)]
+        [InlineData(double.PositiveInfinity, double.PositiveInfinity, 20, 40)]
+        public void StretchedPanel_Measures_Correctly(double availableWidth, double availableHeight, double desiredWidth, double desiredHeight)
+        {
+            using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+            var rect1 = new Rectangle { Height = 20, Width = 20 };
+            var rect2 = new Rectangle { Height = 20, Width = 20 };
+
+            var target = new RelativePanel
+            {
+                VerticalAlignment = Layout.VerticalAlignment.Stretch,
+                HorizontalAlignment = Layout.HorizontalAlignment.Stretch,
+                Children =
+                {
+                    rect1, rect2
+                }
+            };
+
+            RelativePanel.SetBelow(rect2, rect1);
+            target.Measure(new Size(availableWidth, availableHeight));
+            target.Arrange(new Rect(target.DesiredSize));
+            
+            Assert.Equal(desiredWidth, target.DesiredSize.Width);
+            Assert.Equal(desiredHeight, target.DesiredSize.Height);
+        }
     }
 }