How Can I Nest Custom XAML Elements?

2019-04-27 08:47发布

<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.

3条回答
2楼-- · 2019-04-27 09:20

If you don't want to change the UserControl, use a attached behavior. So you just need it there, where the XAML-Compile failed! Only 1 behavior for every UserControl which makes trouble.

in XAML:

 <preview:PreviewControl>
    <i:Interaction.Behaviors>
       <behaviors:UserControlNameBehavior Name="ICanSetNames"/>
    </i:Interaction.Behaviors>
 </preview:PreviewControl>

in C#:

  public class UserControlNameBehavior : Behavior<UserControl>
    {
        public string Name { get; set; }

        protected override void OnAttached()
        {
            this.AssociatedObject.Loaded += OnLoaded;
            base.OnAttached();
        }

        private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            this.AssociatedObject.Name = this.Name;
        }
    }
查看更多
虎瘦雄心在
3楼-- · 2019-04-27 09:38

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!

查看更多
The star\"
4楼-- · 2019-04-27 09:43

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.

查看更多
登录 后发表回答