带附加属性的奇怪WPF错误

时间:2011-04-21 15:20:35

标签: .net wpf

我看到奇怪的行为。我强烈认为它是.net工具链中的一个错误。

重现的步骤:

  1. 创建WPF应用程序。
  2. 在该解决方案中创建类库。
  3. 在类库中定义一些公共类(可以为空)。
  4. 使用附加属性和Window作为目标类在WPF应用程序中定义一些类。
  5. 将其附加到窗口并提供值
  6. 你得到错误:

      

    对象'Window'已经有了   孩子,不能添加''。 '窗口'可以   只接受一个孩子。

    如果更改结构,以便在同一个程序集中具有附加属性和值类的类(可以是类库或Wpf应用程序),它可以正常工作。

    如果您将代码放在内容之后,它也可以正常工作。这给出了错误:

    <Window x:Class="WpfApplication9.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:ClassLibrary1;assembly=ClassLibrary1"
            xmlns:my2="clr-namespace:ClassLibrary1"
            Title="MainWindow" Height="350" Width="525">
    
        <my2:Property.MyProperty>
            <my:ValueClass />
        </my2:Property.MyProperty>
    
        <Grid>
    
        </Grid>
    </Window>
    

    这不是:

    <Grid>
    
    </Grid>    
    
    <my2:Property.MyProperty>
        <my:ValueClass />
    </my2:Property.MyProperty>
    

    有什么想法吗?

    谢谢!

1 个答案:

答案 0 :(得分:3)

这是由编译XAML的自引用方式引起的。虽然您对包含附加属性(应用程序集)的程序集有一个名称空间引用,但是当您需要XAML编译器确定元素语法引用附加属性时,该程序集实际上正处于编译过程中。不是一般的元素。

正如您所发现的那样,在内容之后放置附加属性足以让它即使信息不完整也能做出正确的选择。另一方面,知道这是问题所在,您也可以简单地将附加属性放入外部程序集中,例如放入控件库中,这也可以避免鸡蛋和鸡蛋问题。

在一个完美的世界中,C#编译器和XAML编译器将完全相互集成,这个问题就会消失,但在此之前我们必须使用变通方法。

修改

另一个尝试解释这个因为它有点复杂。

编译应用程序程序集时,它包含C#和XAML。在上面的示例代码中,XAML引用了在同一程序集的C#代码中定义的附加属性。因此,XAML编译器需要具有应用程序集的编译版本,以便知道Property.MyProperty是附加属性。但是C#编译器还无法编译您的应用程序程序集,因为尚未编译XAML。这就是鸡与蛋的问题:C#和XAML都相互依赖。

有些东西必须给予,XAML编译器继续并尝试使用不完整的信息编译应用程序的XAML文件,即使应用程序程序集尚未编译。在这样做的过程中,它可能会出错,就像没有检测到在同一个程序集中定义的附加属性一样。为什么它有时会起作用?我们可以注意到,他们已经付出了一些努力来处理一些常见的情况,所以它确实在大多数情况下似乎工作,但是它并不像你发现的那样一直无法工作。

最简单的解决方案是将附加属性移动到外部程序集中。像控件这样的附加属性通常与库相关联,因此通常不会出现问题。