Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public partial class TabbedPage
NavigationRootManager? _navigationRootManager;
WFrame? _navigationFrame;
bool _connectedToHandler;
Page? _displayedPage;
WFrame NavigationFrame => _navigationFrame ?? throw new ArgumentNullException(nameof(NavigationFrame));
IMauiContext MauiContext => this.Handler?.MauiContext ?? throw new InvalidOperationException("MauiContext cannot be null here");

Expand Down Expand Up @@ -177,6 +178,7 @@ void OnHandlerDisconnected(ElementHandler? elementHandler)
_navigationView = null;
_navigationRootManager = null;
_navigationFrame = null;
_displayedPage = null;
}

void OnTabbedPageAppearing(object? sender, EventArgs e)
Expand Down Expand Up @@ -255,8 +257,15 @@ void OnSelectedMenuItemChanged(NavigationView sender, NavigationViewSelectionCha

void NavigateToPage(Page page)
{
FrameNavigationOptions navOptions = new FrameNavigationOptions();
if (_displayedPage == page)
return;

// Detach content from old page to prevent "Element is already the child of another element" error
if (NavigationFrame.Content is WPage oldPage && oldPage.Content is WContentPresenter oldPresenter)
oldPresenter.Content = null;

CurrentPage = page;
FrameNavigationOptions navOptions = new FrameNavigationOptions();
navOptions.IsNavigationStackEnabled = false;
NavigationFrame.NavigateToType(typeof(WPage), null, navOptions);
}
Expand All @@ -270,7 +279,7 @@ void UpdateCurrentPageContent()

void UpdateCurrentPageContent(WPage page)
{
if (MauiContext == null)
if (MauiContext == null || _displayedPage == CurrentPage)
return;

WContentPresenter? presenter;
Expand All @@ -297,6 +306,7 @@ void UpdateCurrentPageContent(WPage page)
return;

presenter.Content = _currentPage.ToPlatform(MauiContext);
_displayedPage = CurrentPage;
}

void OnNavigated(object sender, UI.Xaml.Navigation.NavigationEventArgs e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
Expand All @@ -12,7 +13,10 @@
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;
using Xunit;
using WContentPresenter = Microsoft.UI.Xaml.Controls.ContentPresenter;
using WFrame = Microsoft.UI.Xaml.Controls.Frame;
using WFrameworkElement = Microsoft.UI.Xaml.FrameworkElement;
using WPage = Microsoft.UI.Xaml.Controls.Page;
using WSolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush;

namespace Microsoft.Maui.DeviceTests
Expand Down Expand Up @@ -197,5 +201,39 @@ await AssertionExtensions.AssertTabItemTextDoesNotContainColor(
tabText, iconColor, tabbedPage.FindMauiContext());
}
}

[Fact(DisplayName = "Issue 32824 - Tab Switch Clears Old Content To Prevent Crash")]
public async Task TabSwitchClearsOldContentToPreventCrash()
{
// https://github.com/dotnet/maui/issues/32824
// When switching tabs, the old ContentPresenter.Content must be cleared
// before navigation to prevent "Element is already the child of another element" crash.
SetupBuilder();

var page1 = new ContentPage { Title = "Tab 1", Content = new Label { Text = "Page 1" } };
var page2 = new ContentPage { Title = "Tab 2", Content = new Label { Text = "Page 2" } };
var tabbedPage = new TabbedPage { Children = { page1, page2 } };

await CreateHandlerAndAddToWindow<TabbedViewHandler>(tabbedPage, handler =>
{
var frame = typeof(TabbedPage)
.GetField("_navigationFrame", BindingFlags.NonPublic | BindingFlags.Instance)
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code uses BindingFlags but the required using directive for System.Reflection is missing from the file. This will cause a compilation error. Add 'using System.Reflection;' to the top of the file with the other using statements.

Copilot uses AI. Check for mistakes.
?.GetValue(tabbedPage) as WFrame;

Assert.NotNull(frame);

var oldPresenter = (frame.Content as WPage)?.Content as WContentPresenter;
Assert.NotNull(oldPresenter);
Assert.NotNull(oldPresenter.Content);

// Switch tabs - oldPresenter.Content should be cleared before navigation
tabbedPage.CurrentPage = page2;

//old presenter content must be null to prevent crash
Assert.Null(oldPresenter.Content);

return Task.CompletedTask;
});
}
}
}
Loading