Description
(It was hard to explain in the title)
We have an application with inbuilt navigation structure that runs in Xamarin with no problem but after porting to MAUI it failed on navigating to a new page.
The error on Android is:
Java.Lang.IllegalStateException: 'The specified child already has a parent. You must call removeView() on the child's parent first.'
Imagine the below structure (Sample reproduction solution provided):
<ContentPage>
<ContentView> <!--Navigation root content holder-->
<!--Anything here is basically dynamically attached to page through navigation infrastructure.
Other UI elements work fine but this element here fails-->
<ContentView Style={SubContent}></ContentView>
</ContentView>
</ContentPage>
The problems seems to be that when content is changing, the inner ContentView elements that have their content set through style would somehow be shared (possibly because static styles are singleton) and that causes the next (incoming) content to try to re-attach the same Content generated by style to the page which then throws the exception.
Steps to Reproduce
- open the example solution
- Run it on Android emulator (What I tested with was Pixel C Api 32)
- Click the button which says
Clicked 0 times
Link to public reproduction project repository
https://github.com/rbakhshi/bugreporting
Version with bug
7.0 (current)
Last version that worked well
Unknown/Other
Affected platforms
Android, I was not able test on other platforms
Affected platform versions
Android Api 32
Did you find any workaround?
Not yet
Relevant log output
Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.g.cs:line 12324
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 35
at Android.Views.ViewGroup.AddView(View child) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Android.Views.ViewGroup.cs:line 1999
at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 44
at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 49
at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Handlers.IContentViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 183
at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 47
at Microsoft.Maui.PropertyMapper.UpdateProperties(IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 82
at Microsoft.Maui.Handlers.ElementHandler.SetVirtualView(IElement view) in D:\a\_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 74
at Microsoft.Maui.Handlers.ViewHandler.SetVirtualView(IElement element) in D:\a\_work\1\s\src\Core\src\Handlers\View\ViewHandler.cs:line 125
at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.ContentViewGroup, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].SetVirtualView(IView view) in D:\a\_work\1\s\src\Core\src\Handlers\View\ViewHandlerOfT.cs:line 53
at Microsoft.Maui.Handlers.ContentViewHandler.SetVirtualView(IView view) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 27
at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.ContentViewGroup, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].SetVirtualView(IElement view) in D:\a\_work\1\s\src\Core\src\Handlers\View\ViewHandlerOfT.cs:line 56
at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Element\Element.Impl.cs:line 64
at Microsoft.Maui.Controls.Element.set_Handler(IElementHandler value) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Element\Element.Impl.cs:line 20
at Microsoft.Maui.Controls.VisualElement.Microsoft.Maui.IElement.set_Handler(IElementHandler value) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\VisualElement\VisualElement.Impl.cs:line 301
at Microsoft.Maui.Platform.ElementExtensions.ToHandler(IElement view, IMauiContext context) in D:\a\_work\1\s\src\Core\src\Platform\ElementExtensions.cs:line 96
at Microsoft.Maui.Platform.ElementExtensions.ToPlatform(IElement view, IMauiContext context) in D:\a\_work\1\s\src\Core\src\Platform\ElementExtensions.cs:line 127
at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 44
at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 49
at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Handlers.IContentViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 183
at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 47
at Microsoft.Maui.PropertyMapper.UpdateProperty(IElementHandler viewHandler, IElement virtualView, String property) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 72
at Microsoft.Maui.Handlers.ElementHandler.UpdateValue(String property) in D:\a\_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 82
at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName) in D:\a\_work\1\s\src\Controls\src\Core\Element.cs:line 383
at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 530
at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 466
at Microsoft.Maui.Controls.BindingExpression.ApplyCore(Object sourceObject, BindableObject target, BindableProperty property, Boolean fromTarget) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 160
at Microsoft.Maui.Controls.BindingExpression.Apply(Boolean fromTarget) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 56
at Microsoft.Maui.Controls.BindingExpression.BindingExpressionPart.<PropertyChanged>b__49_0() in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 750
at Microsoft.Maui.Controls.DispatcherExtensions.DispatchIfRequired(IDispatcher dispatcher, Action action) in D:\a\_work\1\s\src\Controls\src\Core\DispatcherExtensions.cs:line 53
at Microsoft.Maui.Controls.BindingExpression.BindingExpressionPart.PropertyChanged(Object sender, PropertyChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 750
at Microsoft.Maui.Controls.BindingExpression.WeakPropertyChangedProxy.OnPropertyChanged(Object sender, PropertyChangedEventArgs e) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 653
at MauiAppNew.Library.ClickViewModel.OnPropertyChanged(String propertyName) in C:\workspace\net\bugreporting\ClassLibrary1\ClickViewModel.cs:line 61
at MauiAppNew.Library.ClickViewModel.set_Count(Int32 value) in C:\workspace\net\bugreporting\ClassLibrary1\ClickViewModel.cs:line 39
at MauiAppNew.Library.ClickViewModel.<.ctor>b__2_0() in C:\workspace\net\bugreporting\ClassLibrary1\ClickViewModel.cs:line 23
at Microsoft.Maui.Controls.Command.<>c__DisplayClass4_0.<.ctor>b__0(Object o) in D:\a\_work\1\s\src\Controls\src\Core\Command.cs:line 80
at Microsoft.Maui.Controls.Command.Execute(Object parameter) in D:\a\_work\1\s\src\Controls\src\Core\Command.cs:line 122
at Microsoft.Maui.Controls.ButtonElement.ElementClicked(VisualElement visualElement, IButtonElement ButtonElementManager) in D:\a\_work\1\s\src\Controls\src\Core\ButtonElement.cs:line 60
at Microsoft.Maui.Controls.Button.SendClicked() in D:\a\_work\1\s\src\Controls\src\Core\Button.cs:line 179
at Microsoft.Maui.Controls.Button.Microsoft.Maui.IButton.Clicked() in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Button\Button.Impl.cs:line 23
at Microsoft.Maui.Handlers.ButtonHandler.OnClick(IButton button, View v) in D:\a\_work\1\s\src\Core\src\Handlers\Button\ButtonHandler.Android.cs:line 197
at Microsoft.Maui.Handlers.ButtonHandler.ButtonClickListener.OnClick(View v) in D:\a\_work\1\s\src\Core\src\Handlers\Button\ButtonHandler.Android.cs:line 212
at Android.Views.View.IOnClickListenerInvoker.n_OnClick_Landroid_view_View_(IntPtr jnienv, IntPtr native__this, IntPtr native_v) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Android.Views.View.cs:line 2280
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(_JniMarshal_PPL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 121
--- End of managed Java.Lang.IllegalStateException stack trace ---
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5247)
at android.view.ViewGroup.addView(ViewGroup.java:5076)
at android.view.ViewGroup.addView(ViewGroup.java:5016)
at android.view.ViewGroup.addView(ViewGroup.java:4988)
at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30)
at android.view.View.performClick(View.java:7455)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
at android.view.View.performClickInternal(View.java:7432)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28810)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
--- End of managed Java.Lang.IllegalStateException stack trace ---
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5247)
at android.view.ViewGroup.addView(ViewGroup.java:5076)
at android.view.ViewGroup.addView(ViewGroup.java:5016)
at android.view.ViewGroup.addView(ViewGroup.java:4988)
at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30)
at android.view.View.performClick(View.java:7455)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
at android.view.View.performClickInternal(View.java:7432)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28810)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Workaround
You can use ControlTemplate instead of directly setting Content in style:
Change to the XAML of SubContent
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiAppNew.SubContent"
ControlTemplate="{StaticResource SubContentTemplate}">
<!--- removed the style from line above and replaced it with `ControlTemplate` -->
</ContentView>
The control template
<ControlTemplate x:Key="SubContentTemplate">
<Label>
<Label.FormattedText>
<FormattedString>
<Span>SubContent 2</Span>
<Span Text="{Binding BindingContext.Text, Source={RelativeSource FindAncestor, AncestorType={Type ContentView}}}"/>
</FormattedString>
</Label.FormattedText>
</Label>
</ControlTemplate>
Description
(It was hard to explain in the title)
We have an application with inbuilt navigation structure that runs in Xamarin with no problem but after porting to MAUI it failed on navigating to a new page.
The error on Android is:
Imagine the below structure (Sample reproduction solution provided):
The problems seems to be that when content is changing, the inner
ContentViewelements that have their content set through style would somehow be shared (possibly because static styles are singleton) and that causes the next (incoming) content to try to re-attach the same Content generated by style to the page which then throws the exception.Steps to Reproduce
Clicked 0 timesLink to public reproduction project repository
https://github.com/rbakhshi/bugreporting
Version with bug
7.0 (current)
Last version that worked well
Unknown/Other
Affected platforms
Android, I was not able test on other platforms
Affected platform versions
Android Api 32
Did you find any workaround?
Not yet
Relevant log output
Workaround
You can use
ControlTemplateinstead of directly settingContentin style:Change to the XAML of SubContent
The control template