diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs index eb0df4eca87b..79367f87526f 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Android.cs @@ -57,10 +57,19 @@ public void Remove(IView child) _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - if (child?.ToPlatform() is View view) + if (child.Handler?.PlatformView is not null && child.ToPlatform() is View view) { PlatformView.RemoveView(view); } + else + { + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + + if(targetIndex < PlatformView.ChildCount) + { + PlatformView.RemoveViewAt(targetIndex); + } + } } static void Clear(LayoutViewGroup platformView) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Mac.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Mac.cs deleted file mode 100644 index 0a122534e192..000000000000 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Mac.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Microsoft.Maui.Handlers -{ - public partial class LayoutHandler : ViewHandler - { - protected override NSView CreateView() - { - return new NSView(); - } - } -} diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs index 644750214359..3a166de61efd 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs @@ -40,10 +40,20 @@ public void Remove(IView child) _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - if (child?.ToPlatform() is UIElement view) + if (child.Handler?.PlatformView is not null && child.ToPlatform() is UIElement view) { PlatformView.Children.Remove(view); } + else + { + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + + if(targetIndex < PlatformView.Children.Count) + { + var childToRemove = PlatformView.Children[targetIndex]; + PlatformView.Children.Remove(childToRemove); + } + } } public void Clear() diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs b/src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs index a482f55212e9..896fd34f57de 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs @@ -61,10 +61,17 @@ public void Remove(IView child) _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - if (child?.ToPlatform() is PlatformView childView) + if (child.Handler?.PlatformView is not null && child.ToPlatform() is PlatformView childView) { childView.RemoveFromSuperview(); } + else + { + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + + if(targetIndex < PlatformView.Subviews.Length) + PlatformView.Subviews[targetIndex].RemoveFromSuperview(); + } } public void Clear() diff --git a/src/Core/tests/DeviceTests/Handlers/Layout/LayoutHandlerTests.cs b/src/Core/tests/DeviceTests/Handlers/Layout/LayoutHandlerTests.cs index 024d24a28126..b77a1184be93 100644 --- a/src/Core/tests/DeviceTests/Handlers/Layout/LayoutHandlerTests.cs +++ b/src/Core/tests/DeviceTests/Handlers/Layout/LayoutHandlerTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.Maui.DeviceTests.Stubs; using Microsoft.Maui.Handlers; @@ -75,6 +76,30 @@ public async Task HandlerRemovesChildFromNativeLayout() Assert.Equal(0, count); } + [Fact(DisplayName = "Removing Child with DisconnectedHandler doesn't crash")] + public async Task RemovingChildWithDisconnectedHandlerDoesntCrash() + { + var layout = new LayoutStub(); + var slider = new SliderStub(); + var slider2 = new SliderStub(); + layout.Add(slider); + layout.Add(slider2); + + slider.ZIndex = 1; + slider2.ZIndex = 0; + + var handler = await CreateHandlerAsync(layout); + + var count = await InvokeOnMainThreadAsync(() => + { + slider.Handler.DisconnectHandler(); + handler.Invoke(nameof(ILayoutHandler.Remove), new LayoutHandlerUpdate(0, slider)); + return GetNativeChildren(handler).First() == ((IPlatformViewHandler)slider2.Handler).PlatformView; + }); + + Assert.True(count); + } + [Fact(DisplayName = "DisconnectHandler removes child from native layout")] public async Task DisconnectHandlerRemovesChildFromNativeLayout() {