Browse Source

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

Fix RelativePanel crash inside StackPanel
pull/8778/head
Max Katz 4 years ago
committed by GitHub
parent
commit
f9faa6a2f3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      src/Avalonia.Controls/RelativePanel.cs
  2. 29
      tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs

25
src/Avalonia.Controls/RelativePanel.cs

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

29
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, 0, 20, 20), target.Children[0].Bounds);
Assert.Equal(new Rect(0, -20, 20, 20), target.Children[1].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);
}
} }
} }

Loading…
Cancel
Save