Skip to content

Commit

Permalink
Make MeasureInvalidated event work correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
albyrock87 authored and PureWeen committed Aug 15, 2024
1 parent 700fc8f commit 4bb54e7
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 17 deletions.
10 changes: 6 additions & 4 deletions src/Controls/src/Core/LegacyLayouts/Layout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ protected virtual void InvalidateLayout()
/// It is suggested to still call the base method and modify its calculated results.</remarks>
protected abstract void LayoutChildren(double x, double y, double width, double height);

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
}

/// <summary>
/// Invoked whenever a child of the layout has emitted <see cref="VisualElement.MeasureInvalidated" />.
/// Implement this method to add class handling for this event.
Expand Down Expand Up @@ -603,14 +609,10 @@ void OnInternalAdded(View view)
{
InvalidateLayout();
}

view.MeasureInvalidated += OnChildMeasureInvalidated;
}

void OnInternalRemoved(View view, int oldIndex)
{
view.MeasureInvalidated -= OnChildMeasureInvalidated;

OnChildRemoved(view, oldIndex);
if (ShouldInvalidateOnChildRemoved(view))
{
Expand Down
24 changes: 14 additions & 10 deletions src/Controls/src/Core/Page/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,12 @@ protected override void OnBindingContextChanged()
if (TitleView != null)
SetInheritedBindingContext(TitleView, BindingContext);
}

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
}

/// <summary>
/// Indicates that the preferred size of a child <see cref="Element"/> has changed.
Expand Down Expand Up @@ -706,9 +712,6 @@ void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedE
for (var i = 0; i < e.OldItems.Count; i++)
{
var item = (Element)e.OldItems[i];
if (item is VisualElement visual)
visual.MeasureInvalidated -= OnChildMeasureInvalidated;

RemoveLogicalChild(item);
}
}
Expand All @@ -721,20 +724,21 @@ void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedE
{
int insertIndex = index;
if (insertIndex < 0)
{
insertIndex = InternalChildren.IndexOf(item);
}

if (item is VisualElement visual)
InsertLogicalChild(insertIndex, item);

if (item is VisualElement)
{
visual.MeasureInvalidated += OnChildMeasureInvalidated;

InsertLogicalChild(insertIndex, visual);
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
else
InsertLogicalChild(insertIndex, item);


if (index >= 0)
{
index++;
}
}
}
}
Expand Down
33 changes: 30 additions & 3 deletions src/Controls/src/Core/VisualElement/VisualElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,9 +1252,7 @@ protected override void OnChildAdded(Element child)
{
base.OnChildAdded(child);

var view = child as View;

if (view != null)
if (child is View view)
{
ComputeConstraintForView(view);
}
Expand Down Expand Up @@ -1377,6 +1375,35 @@ internal virtual void InvalidateMeasureInternal(InvalidationTrigger trigger)
}

MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(trigger));
(Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, trigger);
}

internal virtual void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
switch (trigger)
{
case InvalidationTrigger.VerticalOptionsChanged:
case InvalidationTrigger.HorizontalOptionsChanged:
// When a child changes its HorizontalOptions or VerticalOptions
// the size of the parent won't change, so we don't have to invalidate the measure
return;
case InvalidationTrigger.RendererReady:
// Undefined happens in many cases, including when `IsVisible` changes
case InvalidationTrigger.Undefined:
MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(trigger));
(Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, trigger);
return;
default:
// When visibility changes `InvalidationTrigger.Undefined` is used,
// so here we're sure that visibility didn't change
if (child.IsVisible)
{
// We need to invalidate measures only if child is actually visible
MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(InvalidationTrigger.MeasureChanged));
(Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, InvalidationTrigger.MeasureChanged);
}
return;
}
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public CollectionViewCoreGalleryContentPage()
// SelectionShouldUpdateBinding (src\Compatibility\ControlGallery\src\Issues.Shared\CollectionViewBoundSingleSelection.cs)
// ItemsFromViewModelShouldBeSelected (src\Compatibility\ControlGallery\src\Issues.Shared\CollectionViewBoundMultiSelection.cs)
TestBuilder.NavButton("Selection Galleries", () => new SelectionGallery(), Navigation),
TestBuilder.NavButton("Item Size Galleries", () => new ItemsSizeGallery(), Navigation),
}
}
};
Expand Down

0 comments on commit 4bb54e7

Please sign in to comment.