Posts Tagged LoadComponent

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


DownloadThe 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!)  

You can download the project from here.  Feel free to use it as you see fit.  

Here’s an example of using it: 

  

public HtmlTextBox()
        {
            var s = ValidateXaml.GetXamlErrors(new System.Uri("/Alchemy.extension;component/Components/HtmlTextBox.xaml", System.UriKind.Relative));
            Debug.WriteLine(s);
            InitializeComponent();
       }   

Caveats

This isn’t going to work too well if removing a node that fails just causes the problem to propagate to a part of the XAML that was previously valid – the only way I can think about solving that requires far more recursion and taking out multiple nodes at each level.  I’d be interested in anyone elses view on this and any other strategies…

You may have a problem with project references, if you do then see the discussion below, hopefully I’ve accounted for most circumstances.

Discussion

Having had the initial idea about this approach I ran into a couple of stumbling blocks which are worth exploring for those who are interested.  

Firstly, when you call InitializeComponent in a UserControl etc – it uses Application.LoadComponent to parse the XAML.  I can’t use that approach because it takes a URI and I need to pass in a string which is the XAML with an element removed.  For this reason my code uses XamlReader to parse the file – the problem there is that it always throws an exception for XAML that contains an x:Class attribute.  My first job then is to strip that out.  

The next attribute problem was much harder to solve.  UserControl xmlns attributes are used to provide reference to components stored in other assemblies. The attribute provides the namespace and the assembly.  The assembly is omitted for other controls that are contained in the same assembly as the problem control.  LoadComponent has no problems with resolving this reference, but XamlReader throws our favorite exception if it isn’t there – this took me a LONG time to figure out.  

So I have to add an “assembly=” extension to the xmlns references that don’t contain one (except the xlmns:x) to ensure that XamlReader will parse a correct file.  I do this by enquiring about the calling assembly and adding its name to the attribute.  

Sounds sensible right?  Well it was a bit more complicated than that – if I just modify the attribute while it is connected to the document, some behind the scenes magic changes all of the things that are referred to by that namespace! Guess what the error is? Yep, “element is already the child of another element” 🙂  

So now I remove the attribute from the document, modify it and put it back – presto!  No unwanted changes and the algorithm finally gets to have a go at parsing the file.

If this attribute modification causes you a problem, you could remove the code and explicitly qualify your project references, this does work, I’ve tried it and would account for a situation in which I accidentally update an xmlns that doesn’t need touching – but this does mean that you won’t be using the VS2010 automatically generated references.  I hope that this won’t normally be a problem.

UPDATE: I’ve modified the source to allow you to pass a parameter that turns off the xmlns modifications – see above comment about explicit assembly references if you set this.  It defaults to “true” which enables the automatic update of references.

, , , , , , ,

7 Comments