Monday, September 13, 2010

Debugging Silverlight “element is already the child of another element” !

The problem
I know how many people are having a problem with the catch-all XAML error “Element is already the child of another element” – it’s been a popular post on this blog and I come across it all of the time.  The real problem is that the exception gives no indication of the area causing the failure, you are forced into playing with the source file and banging your head against the wall.  Well, help is at hand!
I have written a program that helps identify which part of the XAML is going wrong and tells you about it!  Now one caveat – it can only tightly identify a single error that is causing this problem – if more than one thing throws the exception then the best you can hope for is for it to point out the XAML container that contains the code that is failing – such as VisualStateManager.   In most cases it will be more specific, because only one element will have changed and cause the exception to be thrown. This ability is helping me a lot, hopefully it can help you too…
The solution
So here’s what I have done.  I have written a XAML validator that reads in the file and then attempts to process it.  When the file has a problem it starts to prune out nodes in the XAML one XML node at a time (I mean it puts back nodes that didn’t solve the problem and tries the next in sequence).  It does this starting with the nodes that have no children, then the ones with 1, 2 and so on, until it has to remove the entire body – hopefully the error is found long before this.  Using this technique the algorithm tries to give you the most tightly isolated area of the XAML to focus on.
When it identifies a node, it checks whether removing any attribute helps and returns this in addition to the offending XAML if it resolves the issue.
The result is a string describing the XAML and any offending attribute.
This is a debugging tool only – it really slows down the application using it, so don’t call it when you don’t have a problem - but it massively improves your debugging time.  I normally instantiate in the constructor of the failing class and Debug.WriteLine() its result.  It is VITAL that you call it from the assembly that contains the failing XAML – it won’t work if you don’t. (See the discussion below if you want to know why!)
Read more: Mike Talbot's Blog