Avalonia
Avalonia copied to clipboard
Fix RelativePanel crash inside StackPanel
What does the pull request do?
Fix for https://github.com/AvaloniaUI/Avalonia/issues/8624
What is the current behavior?
When you put RelativePanel inside the StackPanel, the RelativePanel will try to take all available space. In the case of the vertical StackPanel, it would try to take infinite height and fail because of it.
What is the updated/expected behavior with this PR?
The Grid, WrapPanel, and DockPanel completely ignore the infinite size, They will limit their height based on the child component's height. The same behavior is applied to the RelativePanel.
Fixed issues
Fixes #8624
When I was working on the issue, I found peculiar logic. In the RelativePanel.MeasureOverride. it measures and resets measurements multiple times. Does someone have idea why it happens?
// RelativePanel.cs
protected override Size MeasureOverride(Size availableSize)
{
_childGraph.Clear();
foreach (Layoutable child in Children)
{
if (child == null)
{
continue;
}
var node = _childGraph.AddNode(child);
node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child));
node.AlignTopWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignTopWithProperty, child));
node.AlignRightWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignRightWithProperty, child));
node.AlignBottomWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignBottomWithProperty, child));
node.LeftOfNode = _childGraph.AddLink(node, GetDependencyElement(LeftOfProperty, child));
node.AboveNode = _childGraph.AddLink(node, GetDependencyElement(AboveProperty, child));
node.RightOfNode = _childGraph.AddLink(node, GetDependencyElement(RightOfProperty, child));
node.BelowNode = _childGraph.AddLink(node, GetDependencyElement(BelowProperty, child));
node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignHorizontalCenterWithProperty, child));
node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignVerticalCenterWithProperty, child));
}
_childGraph.Measure(availableSize); // <== measure first time
_childGraph.Reset(false); // <== reset
var calcWidth = Width.IsNaN() && (HorizontalAlignment != HorizontalAlignment.Stretch);
var calcHeight = Height.IsNaN() && (VerticalAlignment != VerticalAlignment.Stretch);
var boundingSize = _childGraph.GetBoundingSize(calcWidth, calcHeight);
_childGraph.Reset(); // <== reset
_childGraph.Measure(boundingSize); // <== measure second time
return boundingSize;
}
You can test this PR using the following package version. 0.10.999-cibuild0023117-beta
. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]
When I was working on the issue, I found peculiar logic. In the RelativePanel.MeasureOverride. it measures and resets measurements multiple times. Does someone have idea why it happens?
// RelativePanel.cs protected override Size MeasureOverride(Size availableSize) { _childGraph.Clear(); foreach (Layoutable child in Children) { if (child == null) { continue; } var node = _childGraph.AddNode(child); node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child)); node.AlignTopWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignTopWithProperty, child)); node.AlignRightWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignRightWithProperty, child)); node.AlignBottomWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignBottomWithProperty, child)); node.LeftOfNode = _childGraph.AddLink(node, GetDependencyElement(LeftOfProperty, child)); node.AboveNode = _childGraph.AddLink(node, GetDependencyElement(AboveProperty, child)); node.RightOfNode = _childGraph.AddLink(node, GetDependencyElement(RightOfProperty, child)); node.BelowNode = _childGraph.AddLink(node, GetDependencyElement(BelowProperty, child)); node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignHorizontalCenterWithProperty, child)); node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignVerticalCenterWithProperty, child)); } _childGraph.Measure(availableSize); // <== measure first time _childGraph.Reset(false); // <== reset var calcWidth = Width.IsNaN() && (HorizontalAlignment != HorizontalAlignment.Stretch); var calcHeight = Height.IsNaN() && (VerticalAlignment != VerticalAlignment.Stretch); var boundingSize = _childGraph.GetBoundingSize(calcWidth, calcHeight); _childGraph.Reset(); // <== reset _childGraph.Measure(boundingSize); // <== measure second time return boundingSize; }
Ported from: https://github.com/HandyOrg/HandyControl/blob/master/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs#L220-L228
The reset call has an argument and has different behavior.
@byme8 any chance to add a unit test here?
https://github.com/AvaloniaUI/Avalonia/blob/master/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs
You can test this PR using the following package version. 0.10.999-cibuild0023221-beta
. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]
@byme8 any chance to add a unit test here?
https://github.com/AvaloniaUI/Avalonia/blob/master/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs
I will add tests
@danwalmsley I added tests for a stretched relative panel.
You can test this PR using the following package version. 0.10.999-cibuild0023266-beta
. (feed url: https://nuget.avaloniaui.net/repository/avalonia-all/index.json) [PRBUILDID]