Skip to content

Commit 8a8deda

Browse files
maxkatz6danwalmsley
authored andcommitted
Merge pull request AvaloniaUI#7555 from AvaloniaUI/fixes/7552-visibility-layout-invalidation
Fix visibility layout invalidation
1 parent 8ad1887 commit 8a8deda

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

src/Avalonia.Layout/Layoutable.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ public class Layoutable : Visual, ILayoutable
141141
static Layoutable()
142142
{
143143
AffectsMeasure<Layoutable>(
144-
IsVisibleProperty,
145144
WidthProperty,
146145
HeightProperty,
147146
MinWidthProperty,
@@ -781,6 +780,25 @@ protected virtual void OnMeasureInvalidated()
781780
{
782781
}
783782

783+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
784+
{
785+
base.OnPropertyChanged(change);
786+
787+
if (change.Property == IsVisibleProperty)
788+
{
789+
DesiredSize = default;
790+
791+
// All changes to visibility cause the parent element to be notified.
792+
this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);
793+
794+
// We only invalidate outselves when visibility is changed to true.
795+
if (change.GetNewValue<bool>())
796+
{
797+
InvalidateMeasure();
798+
}
799+
}
800+
}
801+
784802
/// <inheritdoc/>
785803
protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent)
786804
{

tests/Avalonia.Layout.UnitTests/LayoutableTests.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,103 @@ public void LayoutManager_LayoutUpdated_Is_Unsubscribed_When_Detached_From_Tree(
320320
Times.Once);
321321
}
322322

323+
[Fact]
324+
public void Making_Control_Invisible_Should_Invalidate_Parent_Measure()
325+
{
326+
Border child;
327+
var target = new StackPanel
328+
{
329+
Children =
330+
{
331+
(child = new Border
332+
{
333+
Width = 100,
334+
}),
335+
}
336+
};
337+
338+
target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
339+
target.Arrange(new Rect(target.DesiredSize));
340+
341+
Assert.True(target.IsMeasureValid);
342+
Assert.True(target.IsArrangeValid);
343+
Assert.True(child.IsMeasureValid);
344+
Assert.True(child.IsArrangeValid);
345+
346+
child.IsVisible = false;
347+
348+
Assert.False(target.IsMeasureValid);
349+
Assert.False(target.IsArrangeValid);
350+
Assert.True(child.IsMeasureValid);
351+
Assert.True(child.IsArrangeValid);
352+
}
353+
354+
[Fact]
355+
public void Making_Control_Visible_Should_Invalidate_Own_And_Parent_Measure()
356+
{
357+
Border child;
358+
var target = new StackPanel
359+
{
360+
Children =
361+
{
362+
(child = new Border
363+
{
364+
Width = 100,
365+
IsVisible = false,
366+
}),
367+
}
368+
};
369+
370+
target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
371+
target.Arrange(new Rect(target.DesiredSize));
372+
373+
Assert.True(target.IsMeasureValid);
374+
Assert.True(target.IsArrangeValid);
375+
Assert.True(child.IsMeasureValid);
376+
Assert.False(child.IsArrangeValid);
377+
378+
child.IsVisible = true;
379+
380+
Assert.False(target.IsMeasureValid);
381+
Assert.False(target.IsArrangeValid);
382+
Assert.False(child.IsMeasureValid);
383+
Assert.False(child.IsArrangeValid);
384+
}
385+
386+
[Fact]
387+
public void Measuring_Invisible_Control_Should_Not_Invalidate_Parent_Measure()
388+
{
389+
Border child;
390+
var target = new StackPanel
391+
{
392+
Children =
393+
{
394+
(child = new Border
395+
{
396+
Width = 100,
397+
}),
398+
}
399+
};
400+
401+
target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
402+
target.Arrange(new Rect(target.DesiredSize));
403+
404+
Assert.True(target.IsMeasureValid);
405+
Assert.True(target.IsArrangeValid);
406+
Assert.Equal(new Size(100, 0), child.DesiredSize);
407+
408+
child.IsVisible = false;
409+
Assert.Equal(default, child.DesiredSize);
410+
411+
target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
412+
target.Arrange(new Rect(target.DesiredSize));
413+
child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
414+
415+
Assert.True(target.IsMeasureValid);
416+
Assert.True(target.IsArrangeValid);
417+
Assert.Equal(default, child.DesiredSize);
418+
}
419+
323420
private class TestLayoutable : Layoutable
324421
{
325422
public Size ArrangeSize { get; private set; }

0 commit comments

Comments
 (0)