Skip to content

Commit

Permalink
Merge pull request #7555 from AvaloniaUI/fixes/7552-visibility-layout…
Browse files Browse the repository at this point in the history
…-invalidation

Fix visibility layout invalidation
  • Loading branch information
maxkatz6 authored and danwalmsley committed May 24, 2022
1 parent 8ad1887 commit 8a8deda
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/Avalonia.Layout/Layoutable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ public class Layoutable : Visual, ILayoutable
static Layoutable()
{
AffectsMeasure<Layoutable>(
IsVisibleProperty,
WidthProperty,
HeightProperty,
MinWidthProperty,
Expand Down Expand Up @@ -781,6 +780,25 @@ protected virtual void OnMeasureInvalidated()
{
}

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

if (change.Property == IsVisibleProperty)
{
DesiredSize = default;

// All changes to visibility cause the parent element to be notified.
this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);

// We only invalidate outselves when visibility is changed to true.
if (change.GetNewValue<bool>())
{
InvalidateMeasure();
}
}
}

/// <inheritdoc/>
protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent)
{
Expand Down
97 changes: 97 additions & 0 deletions tests/Avalonia.Layout.UnitTests/LayoutableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,103 @@ public void LayoutManager_LayoutUpdated_Is_Unsubscribed_When_Detached_From_Tree(
Times.Once);
}

[Fact]
public void Making_Control_Invisible_Should_Invalidate_Parent_Measure()
{
Border child;
var target = new StackPanel
{
Children =
{
(child = new Border
{
Width = 100,
}),
}
};

target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
target.Arrange(new Rect(target.DesiredSize));

Assert.True(target.IsMeasureValid);
Assert.True(target.IsArrangeValid);
Assert.True(child.IsMeasureValid);
Assert.True(child.IsArrangeValid);

child.IsVisible = false;

Assert.False(target.IsMeasureValid);
Assert.False(target.IsArrangeValid);
Assert.True(child.IsMeasureValid);
Assert.True(child.IsArrangeValid);
}

[Fact]
public void Making_Control_Visible_Should_Invalidate_Own_And_Parent_Measure()
{
Border child;
var target = new StackPanel
{
Children =
{
(child = new Border
{
Width = 100,
IsVisible = false,
}),
}
};

target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
target.Arrange(new Rect(target.DesiredSize));

Assert.True(target.IsMeasureValid);
Assert.True(target.IsArrangeValid);
Assert.True(child.IsMeasureValid);
Assert.False(child.IsArrangeValid);

child.IsVisible = true;

Assert.False(target.IsMeasureValid);
Assert.False(target.IsArrangeValid);
Assert.False(child.IsMeasureValid);
Assert.False(child.IsArrangeValid);
}

[Fact]
public void Measuring_Invisible_Control_Should_Not_Invalidate_Parent_Measure()
{
Border child;
var target = new StackPanel
{
Children =
{
(child = new Border
{
Width = 100,
}),
}
};

target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
target.Arrange(new Rect(target.DesiredSize));

Assert.True(target.IsMeasureValid);
Assert.True(target.IsArrangeValid);
Assert.Equal(new Size(100, 0), child.DesiredSize);

child.IsVisible = false;
Assert.Equal(default, child.DesiredSize);

target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
target.Arrange(new Rect(target.DesiredSize));
child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

Assert.True(target.IsMeasureValid);
Assert.True(target.IsArrangeValid);
Assert.Equal(default, child.DesiredSize);
}

private class TestLayoutable : Layoutable
{
public Size ArrangeSize { get; private set; }
Expand Down

0 comments on commit 8a8deda

Please sign in to comment.