maui icon indicating copy to clipboard operation
maui copied to clipboard

Adding/Removing layout children does not invalidate measures

Open albyrock87 opened this issue 1 year ago • 0 comments

Description

I'm using a simple BindableLayout to add and remove children dynamically from VerticalStackLayout and I realized MeasureInvalidated event is not being fired when children changes.

So I went inside MAUI repo and added a couple of unit test which in fact are failing:

static IViewHandler ListenForInvalidation(IView view)
{
	var handler = Substitute.For<IViewHandler>();
	view.Handler = handler;
	handler.ClearReceivedCalls();
	return handler;
}
		
[Fact]
public void AddingChildInvalidatesLayoutHandler()
{
	var layout = new VerticalStackLayout();

	var handler = ListenForInvalidation(layout);
	layout.Add(new Label());
	AssertInvalidated(handler);
}

[Fact]
public void AddingChildInvalidatesLayout()
{
	var layout = new VerticalStackLayout();
	var invalidated = false;
	layout.MeasureInvalidated += (_, _) => invalidated = true;

	layout.Add(new Label());
	Assert.True(invalidated);
}

Note: the Grid from Compatibility package does behave correctly, in fact you have a working unit test there:

[Fact]
public void TestAddCell()
{
	var layout = new Grid();
	bool preferredSizeChanged = false;
	layout.MeasureInvalidated += (sender, args) => preferredSizeChanged = true;

	Assert.False(preferredSizeChanged);

	layout.Children.Add(new Label(), 0, 0);

	Assert.True(preferredSizeChanged);
}

I would propose a PR but I'm not sure which approach you would like to take here as the fix should probably go in Layout base class or maybe in VisualElement idk.

Steps to Reproduce

  1. Create a VerticalStackLayout
  2. Subscribe to MeasureInvalidated
  3. Add a child
  4. Observe nothing was triggered

Link to public reproduction project repository

No response

Version with bug

8.0.6

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS, I was not able test on other platforms

Affected platform versions

No response

Did you find any workaround?

Manually trigger the event ((IVisualElementController)layout).InvalidateMeasure(InvalidationTrigger.MeasureChanged); which is something that makes BindableLayout basically unusable in combination with Binding on ItemSource because we have to subscribe twice using the view code behind.

Relevant log output

No response

albyrock87 avatar Jan 26 '24 16:01 albyrock87