【问题标题】:How Can I Nest Custom XAML Elements?如何嵌套自定义 XAML 元素?
【发布时间】:2010-11-13 11:38:45
【问题描述】:
<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>  

这是在其他文件中...

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

还有……

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

一切正常,除了第二个元素。
我收到错误:
无法在元素“ElementType”上设置名称属性值“SecondElementName”。 “ElementType”在元素“ElementType”的范围内,当它在另一个范围内定义时,它已经注册了一个名称。

自定义网格定义正确。如果我取出属性,代码将编译并运行 ---

x:Name="SecondElementName"  

---在Window1.xaml中

是什么导致了这个错误?我该如何解决?我需要将这些自定义网格中的一个嵌套在另一个网格中,并且我需要它们的名称,以便我可以将它们绑定到单独的数据。

提前致谢。

【问题讨论】:

    标签: wpf xaml .net-3.5 grid nested


    【解决方案1】:

    为了了解如何处理嵌套标记对象,XAML 解析器将查看 .NET 类是否定义了默认“内容”属性以用作此类子对象的容器。这是通过“ContentPropertyAttribute”完成的。

    在您的情况下,因为我想您希望嵌套对象进入网格内部,并且由于网格的子级进入“儿童”属性集合,您只需要执行以下操作:

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

    如果在向控件添加子控件时需要执行一些逻辑(例如,只允许某些类型成为 ElementType 控件的子控件),则可以改为从 IAddChild 继承,并实现 AddChild 和 AddText 方法。

    至于命名问题,似乎只有无视控件才能在实例化范围内命名子项。因此,基本上,您可以在 ElementType.xaml 中命名子项,但不能在您实例化 ElementType 的其他标记中命名子项。我想这是因为他们优化逻辑树或其他东西的方式。 另一方面,无外观控件是只有代码的控件。所以如果你把你的类变成一个简单的旧的 Grid 空子类,它就可以工作:

    public class ElementType : Grid
    {
    }
    

    耶!更少的代码!

    【讨论】:

    • 这也很有趣,但它仍然不允许我给父元素类型对象和子元素类型对象赋予不同的名称。有谁知道我怎样才能让它们彼此分开命名?
    • 哦,是的,对不起...我会在上面完成我的答案。
    【解决方案2】:

    如果您想要一个在另一个中,您需要将内部的一个放在第一个的 Content 属性中:

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

    另外,我不确定你想在这里完成什么,但我很害怕。

    【讨论】:

    • 听起来这是正确的方向。关于你的最后一句:哈!我故意遗漏了任何会泄露细节的东西——相信我,你不想知道。关于您的解决方案,我收到一个错误:“在类型'ElementType'中找不到可附加属性'Content'”我已经尝试使用“Grid.Content”代替它,但我得到了大致相同的错误。还有什么想法吗?
    • 我的意思是“儿童”,而不是内容。不过,看起来你明白了。
    【解决方案3】:

    如果您不想更改 UserControl,请使用附加行为。所以你只需要它,XAML 编译失败的地方!每个 UserControl 只有 1 个行为会造成麻烦。

    在 XAML 中:

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

    在 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;
            }
        }
    

    【讨论】:

    • 什么是行为类?我是什么:?
    猜你喜欢
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2019-05-08
    相关资源
    最近更新 更多