Silverlight App not working as expected in FireFox, IE shows error message “Unhandled Error in Silverlight 2 Application - Element is already the child of another element”
Problem Description
This exception is thrown in a Silverlight 2 App while trying to show and hide System.Windows.Controls.TabItem in System.Windows.Controls.TabControl
Steps to Recreate
browse to http://debuggingblog.com/sl/project1/default.html and click on button “Show Angelina” 3 times
Debugging Silverlight app using WinDbg
We will be analyzing a memory dump of IE on System.InvalidOperationException
1. We have the following two InvalidOperationException exception objects on managed heap
0:007> !dumpheap -type System.InvalidOperationException
Address MT Size
1013c79c 0f1ff824 72
1015addc 0f1ff824 72
total 2 objects
Statistics:
MT Count TotalSize Class Name
0f1ff824 2 144 System.InvalidOperationException
Total 2 objects
2. Lets get the stack trace when this exception occured
0:007> !pe 1013c79c
Exception object: 1013c79c
Exception type: System.InvalidOperationException
Message: Element is already the child of another element.
InnerException: <none>
StackTrace (generated):
SP IP Function
021FF640 0F40F06A !MS.Internal.XcpImports.CheckHResult(UInt32)+0×32
021FF64C 0E3A4CE9 !MS.Internal.XcpImports.SetValue(MS.Internal.INativeCoreTypeWrapper, System.Windows.DependencyProperty, System.Windows.DependencyObject)+0xa9
021FF680 0E3A4118 !MS.Internal.XcpImports.SetValue(MS.Internal.INativeCoreTypeWrapper, System.Windows.DependencyProperty, System.Object)+0×100
021FF71C 0E3A3FBC !System.Windows.DependencyObject.SetObjectValueToCore(System.Windows.DependencyProperty, System.Object)+0×1c4
021FF760 0E3A1CBB !System.Windows.DependencyObject.SetValueInternal(System.Windows.DependencyProperty, System.Object, Boolean, Boolean, Boolean)+0×503
021FF834 0E3A17A1 !System.Windows.DependencyObject.SetValueInternal(System.Windows.DependencyProperty, System.Object)+0×21
021FF848 0E3A1763 !System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty, System.Object)+0×1b
021FF85C 0E3D68D7 !System.Windows.Controls.ContentControl.set_Content(System.Object)+0×37
021FF870 0E3212CF !SilverlightApplication1.Page.ShowContent()+0×57
021FF880 0E3208BE !SilverlightApplication1.Page.ShowHideAngelina_Click(System.Object, System.Windows.RoutedEventArgs)+0×76
021FF898 0E4099B5 !System.Windows.Controls.Primitives.ButtonBase.OnClick()+0×5d
021FF8B0 0E40993F !System.Windows.Controls.Button.OnClick()+0×47
021FF8C0 0E40986D !System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs)+0×85
021FF8D0 0E4097D1 !System.Windows.Controls.Control.OnMouseLeftButtonUp(System.Windows.Controls.Control, System.EventArgs)+0×41
021FF8E0 0E36C887 !MS.Internal.JoltHelper.FireEvent(IntPtr, IntPtr, Int32, System.String)+0×1b7
3. This exception occured while trying to Set the Content of a Control, so lets find out what is this content and who holds this UIElement, lets get the IL of method SilverlightApplication1.Page.ShowContent()
0:007> !dumpil 0f224060
ilAddr = 0f4607f8
IL_0000: ldarg.0
IL_0001: newobj System.Windows.Controls.TabItem::.ctor // A new TabItem object is created
IL_0006: stfld SilverlightApplication1.Page::item
IL_000b: ldarg.0
IL_000c: ldfld SilverlightApplication1.Page::item
IL_0011: ldstr “Angelina Jolie”
IL_0016: callvirt System.Windows.Controls.TabItem::set_Header
IL_001b: ldarg.0
IL_001c: ldfld SilverlightApplication1.Page::item//Get the reference to a TabItem object created earlier
IL_0021: ldarg.0
IL_0022: ldfld SilverlightApplication1.Page::content
IL_0027: callvirt System.Windows.Controls.ContentControl::set_Content //Set_Content is called with SilverlightApplication1.Page object’s data member content
IL_002c: ldarg.0
IL_002d: ldfld SilverlightApplication1.Page::TabList
IL_0032: callvirt System.Windows.Controls.ItemsControl::get_Items
IL_0037: ldarg.0
IL_0038: ldfld SilverlightApplication1.Page::item
We have 2 interesting objects TabItem and SilverlightApplication1.Page::content here
4. First get the address of SilverlightApplication1.Page::content object which is being set in TabItem because that’s what resulting in exception
0:007> !do 1003b3c0
Name: SilverlightApplication1.Page
Fields:
MT Field Offset Type VT Attr Value Name
0f42e730 400000d 58 …Windows.UIElement 0 instance 1011c0e8 content
0:007> !dumpheap -mt 0e396648
Address MT Size
1003ed3c 0e396648 140
101276a0 0e396648 140
1013c050 0e396648 140
total 3 objects
Statistics:
MT Count TotalSize Class Name
0e396648 3 420 System.Windows.Controls.TabItem
Total 3 objects
We have 3 TabItem objects on heap and the address of the content object(UIElement) is 1011c0e8
5. The next step to find out is which TabItem object has this UIElement and why is this TabItem object still around.
0:007> !dumpheap -mt 0e396648
Address MT Size
1003ed3c 0e396648 140
101276a0 0e396648 140
1013c050 0e396648 140
total 3 objects
0:007> !do 101276a0
Name: System.Windows.Controls.TabItem
MethodTable: 0e396648
EEClass: 0e3bb768
Size: 140(0×8c) bytes
File: System.Windows.Controls, Version=2.0.5.0, Culture=neutral
Fields:
MT Field Offset Type VT Attr Value Name
0ec444e8 40002b4 34 System.Object 0 instance 1011c0e8 _treeContent
0:007> !gcroot 101276a0
Note: Roots found on stacks may be false positives. Run “!help gcroot” for
more info.
Scan Thread 7 OSTHread 1710
Scan Thread 27 OSTHread 1200
Scan Thread 28 OSTHread 1278
Scan Thread 31 OSTHread 1488
6. TabItem object with address = 0e396648 has the reference to content object 1011c0e8 and this object is not rooted so that means this object is ready to be garbage collected.
There is already a TabItem object on managed heap holding reference to the same content object which is being assigned to new TabItem object on SilverlightApplication1.Page.ShowHideAngelina_Click(), that’s why we get System.InvaildOperationException with the error message “Element is already the child of another element”
7. You can get the address of Method Description for each of the methods in SilverlightApplication1.Page
0:007> !dumpmt -md 0f224094
————————————–
MethodDesc Table
Entry MethodDesc JIT Name
0e320848 0f224038 JIT SilverlightApplication1.Page.ShowHideAngelina_Click(System.Object,
0e321300 0f224058 JIT SilverlightApplication1.Page.HideContent()
0e321278 0f224060 JIT SilverlightApplication1.Page.ShowContent()
Let’s look at the implementation of ShowHideAngelina_Click
0:007> !dumpil 0f224038
ilAddr = 0f46071c
IL_0012: ldstr “Show”
IL_0017: callvirt System.String::Contains
IL_001c: brfalse.s IL_003f
IL_001e: ldloc.0
IL_0039: call SilverlightApplication1.Page::ShowContent
IL_003e: ret
IL_003f: ldloc.0
IL_004a: ldarg.0
IL_004b: call SilverlightApplication1.Page::HideContent
IL_0050: ret
This method checks the Text of the button and calls ‘ShowContent’ if the text =“Show” otherwise calls ‘HideContent’, so let’s look at HideContent implementation
0:007> !dumpil 0f224058
ilAddr = 0f4607d6
IL_0000: ldarg.0
IL_0001: ldfld SilverlightApplication1.Page::item
IL_0006: brfalse.s IL_001f
IL_0008: ldarg.0
IL_0009: ldfld SilverlightApplication1.Page::TabList
IL_000e: callvirt System.Windows.Controls.ItemsControl::get_Items
IL_0013: ldarg.0
IL_0014: ldfld SilverlightApplication1.Page::item
IL_0019: callvirt class [System.Windows]System.Windows.PresentationF◆䷒¥⽫Ż�::Remove
IL_001e: pop
IL_001f: ret
HideContent calls TabList.get_Items and remove the TabItem from System.Windows.Control.TabControl
Resolution
HideContent() method removes the TabItem from TabControl.Items so unless TabItem is Garbage Collected removed TabItem will still hold the reference to Content UIElement. You can quickly fix this issue by assiging Content = null, when that item is removed as shown below in HideContent
//OLD Buggy Implementation
private void HideContent()
{
if (item != null)
this.TabList.Items.Remove(item);
}
//new implementation to make sure Content is set to null
private void HideContent()
{
item.Content = null; //assign TabItem Content = NULL
if (item != null)
this.TabList.Items.Remove(item);
}
Tags: Silverlight, WinDbg