Andrey
Andrey

Reputation: 60055

Weird WPF error with attached propery

I see strange behavior. I have a strong feeling that it is a bug in .net toolchain.

Steps to reproduce:

  1. Create WPF application.
  2. Create Class Library in that solution.
  3. Define some public class (can be empty) in Class Library.
  4. Define some class in WPF application with attached property and Window as target class.
  5. Attach it to Window and provide value

And you get error:

The object 'Window' already has a child and cannot add ''. 'Window' can accept only one child.

If you change structure so that class with attached property and value class in same assembly (can be either Class Library or Wpf Application) it works fine.

Also it works fine if you put the code after content. This gives error:

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

This does not:

<Grid>

</Grid>    

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

Any ideas?

Thanks!

Upvotes: 3

Views: 1654

Answers (1)

Rick Sladkey
Rick Sladkey

Reputation: 34240

This is caused by the self-referential way that XAML is compiled. Although you have a namespace reference to the assembly containing the attached property, the application assembly, that very assembly is in fact in the process of being compiled at the time you need the XAML compiler to decide that the element syntax refers to an attached property and not an ordinary element.

As you have discovered, putting the attached property after the content is enough of a hint to get it to make the right choice even with incomplete information. On the other hand, knowing that this is the problem, you can also simply put the attached property into an external assembly, for example into the control library, and this will also avoid the chicken-and-the-egg problem.

In a perfect world the C# compiler and the XAML compiler would be fully integrated with each other and this problem would go away but until then we'll have to use workarounds.

Edit:

Another try to explain this because it is a little complicated.

When you compile your application assembly, it contains both C# and XAML. In the sample code above the XAML refers to an attached property defined in the C# code of the same assembly. So the XAML compiler needs to have a compiled version of your application assembly in order to know that Property.MyProperty is an attached property. But the C# compiler can't compile your application assembly yet because the XAML hasn't been compiled. This is the chicken-and-the-egg problem: the C# and XAML both depend on each other.

Something has got to give and the XAML compiler goes ahead and tries to compile your application's XAML files with incomplete information, even though the application assembly hasn't been compiled yet. In the course of doing this it can make mistakes like not detecting attached properties defined in the same assembly. Why does it work sometimes? We can note that they have gone to some effort to handle some common cases so it does appear to work most of the time but nevertheless it does not work all of the time as you have discovered.

The easiest solution is to move your attached property into an external assembly. Attached properties like controls are generally associated with libraries anyway so the problem doesn't usually arise.

Upvotes: 4

Related Questions