Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can I Nest Custom XAML Elements?

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1">
    <Grid>
        <local:ElementType x:Name="FirstElementName">
            <local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" />
        </local:ElementType>
    </Grid>
</Window>  

And this is in other files ...

<Grid x:Name="InternalElementName" x:Class="WpfApplication1.ElementType"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1">
</Grid>  

And ...

public partial class ElementType : System.Windows.Controls.Grid { }  

Everything works fine, except the second element.
I get the error:
Cannot set Name attribute value 'SecondElementName' on element 'ElementType'. 'ElementType' is under the scope of element 'ElementType', which already had a name registered when it was defined in another scope.

The custom grids are defined properly. The code will compile and run if I take out the property ---

x:Name="SecondElementName"  

--- in Window1.xaml

What is causing this error? How do I get around it? I need to nest one of these custom grids inside the other one, and I need names on both of them so I can bind them to seperate data.

Thanks in advance.

like image 388
Giffyguy Avatar asked Jul 23 '09 17:07

Giffyguy


2 Answers

In order to know what to do with nested markup objects, the XAML parser will, among other things, look at whether the .NET class defines a default "content" property to use as a container for such children. This is done with the "ContentPropertyAttribute".

In your case, since I guess you want nested objects to go inside the Grid, and since the children of a grid go in the "Children" property collection, you just need to do the following:

[ContentProperty("Children")]
public partial class ElementType : Grid
{
    // your code here...
}

If you need to do some logic when adding children to your control (e.g. only allow certain types to be children of your ElementType control), you can instead inherit from IAddChild, and implement the AddChild and AddText methods.

As for the naming problem, it seems that only lookless controls can have named children in an instanced scope. So basically, you can have named children inside ElementType.xaml, but not named children in other markup where you instantiate ElementType. I guess it's because of the way they optimize the logical tree or something. A lookless control, on the other hand, is a control with only code. So if you turn your class into a plain old empty subclass of Grid, it works:

public class ElementType : Grid
{
}

Yay! Less code!

like image 192
Ludovic Chabant Avatar answered Oct 18 '22 00:10

Ludovic Chabant


If you want one within the other, you'd want to put the inner one in the Content property of the first:

<local:ElementType x:Name="FirstElementName">
    <local:ElementType.Content>
        <local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" />
    </local:ElementType.Content>
</local:ElementType>

Also, I'm not sure what you are trying to accomplish here, but I fear it.

like image 21
Anderson Imes Avatar answered Oct 18 '22 00:10

Anderson Imes