You might, for some reason, be building some XAML in code rather than markup. Starting with this XAML:

<!-- XAML markup --> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=“Auto” /> <ColumnDefinition Width=“Auto” /> </Grid.ColumnDefinitions> </Grid>

Here’s a flawed attempt to create the grid in code.

// C# var autoWidth = new ColumnDefinition() { Width = GridLength.Auto }; var grid = new Grid() { ColumnDefinitions = { autoWidth, autoWidth } };

We create a column definition whose Width is Auto, and then create a grid whose ColumnDefinitions is two columns, namely two of our Auto columns.

This throws a confusing exception.

System.Runtime.InteropServices.COMException (0x800F1000): No installed components were detected.

What do you mean, no installed components were detected? Why does something need to be installed at all? Do I have to install a special component to be able to create XAML elements from code?

Okay, the first problem is an error code collision. The error message text is coming from error number 0x800F1000 which is SPAPI_E_ERROR_NOT_INSTALLED and belongs to the SETUPAPI facility. Unfortunately, XAML decided to put some of its error codes in the same facility, resulting in an error code collision. XAML defined error code number 0x800F1000 to mean “invalid operation” but gave it the same number as SPAPI_E_ERROR_NOT_INSTALLED. Therefore, when various components try to decide the error code, they come up with the setup error instead of the XAML error.

Another XAML error code collision is “X is not a valid value for property Y” which has the numeric value 0x800F1001 and which collides with SPAPI_E_BAD_SECTION_NAME_LINE.

So the real problem has nothing to do with installed components. That’s just an unfortunate decode of the error code.

Fortunately, XAML provides a details string, which is easily overlooked because it’s two lines away and looks like part of another paragraph.

System.Runtime.InteropServices.COMException (0x800F1000): No installed components were detected.

Element is already the child of another element. Source: Cannot evaluate the exception source.

The problem is that we are reusing the same ColumnDefinition object to describe two different columns. The markup creates two different ColumnDefinition objects, but our code version creates one object and inserts it twice.

To make our code equivalent to the markup, we have to create two ColumnDefinition objects, because that’s what the markup does.

// C# var autoWidth1 = new ColumnDefinition() { Width = GridLength.Auto }; var autoWidth2 = new ColumnDefinition() { Width = GridLength.Auto }; var grid = new Grid() { ColumnDefinitions = { autoWidth1, autoWidth2 } };

And since we’re not reusing the column definition, we don’t need to give it a name.

// C# var grid = new Grid() { ColumnDefinitions = { new ColumnDefinition() { Width = GridLength.Auto }, new ColumnDefinition() { Width = GridLength.Auto } } };

It’s convenient that this code does resemble the original XAML.

We thought we were doing the right thing by reusing an existing object with identical properties, but the XAML tree is a tree, and you can’t insert the same node into a tree in two different locations.

The post Trying to build a XAML tree in code throws a “No installed components were detected” exception appeared first on The Old New Thing.


From The Old New Thing via this RSS feed