diff --git a/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs b/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs index 420072552a7f..b1680b9adc34 100644 --- a/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs +++ b/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs @@ -1,6 +1,7 @@ #nullable disable using Microsoft.Maui; using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Handlers.Items2; using Microsoft.Maui.Controls.Internals; using ObjCRuntime; using UIKit; @@ -16,22 +17,37 @@ public static void UpdateText(this UILabel platformLabel, Label label) switch (label.TextType) { case TextType.Html: - // NOTE: Setting HTML text this will crash with some sort of consistency error. + // NOTE: Setting HTML text like this will crash with some sort of consistency error. + // when inside a CV1 (CollectionView/CarouselView handler v1) layout pass. // https://github.com/dotnet/maui/issues/25946 - // Here we have to dispatch back the the main queue to avoid the crash. - // This is observed with CarouselView 1 but not with 2, so hopefully this - // will be just disappear once we switch. - CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => + // CV2 (the default handler in .NET 10) does NOT have this crash. + if (IsPlatformLabelInsideCV2Cell(platformLabel)) { + // Synchronous: safe in CV2, avoids the two-pass jitter. + // No InvalidateMeasure needed — text is already correct when measured. platformLabel.UpdateTextHtml(text); - if (label.Handler is LabelHandler labelHandler) - Label.MapFormatting(labelHandler, label); + if (label.Handler is LabelHandler labelHandlerSync) + { + Label.MapFormatting(labelHandlerSync, label); + } + } + else + { + CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => + { + platformLabel.UpdateTextHtml(text); + + if (label.Handler is LabelHandler labelHandler) + { + Label.MapFormatting(labelHandler, label); + } - // NOTE: Because we are updating text outside the normal layout - // pass, we need to invalidate the measure for the next pass. - label.InvalidateMeasure(); - }); + // NOTE: Because we are updating text outside the normal layout + // pass, we need to invalidate the measure for the next pass. + label.InvalidateMeasure(); + }); + } break; default: @@ -49,5 +65,20 @@ public static void UpdateText(this UILabel platformLabel, Label label) break; } } + + // Walks the native UIKit superview chain to determine if this UILabel lives inside a CV2 cell. + static bool IsPlatformLabelInsideCV2Cell(UILabel platformLabel) + { + var superview = platformLabel.Superview; + while (superview is not null) + { + if (superview is ItemsViewCell2) + { + return true; + } + superview = superview.Superview; + } + return false; + } } }