WPF: Cannot set properties on property elements weirdness

10,313

Solution 1

I can explain what is going wrong and how to fix it.

First,

<l:CustomPanel>
  <l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />

is a simple syntax error. The <l:CustomPanel.Caption> syntax does not accept XML attributes - the property value must be within the element.

This is proper property element syntax:

<l:CustomPanel>    
  <l:CustomPanel.Caption>  
    <TextBlock Text="Caption text" FontSize="18" Foreground="White" />   
  </l:CustomPanel.Caption>  
</l:CustomPanel>

but:

  1. Property element syntax works only with DependencyProperties (so it didn't work with your CLR property) and
  2. Property element syntax always honors the ContentPropertyAttribute of the property type

Since TextBlock has a [ContentPropertyAttribute("Inlines")], the property element syntax is trying to add the TextBlock to the Inlines collection.

The solution is simple: Declare your property as a DependencyProperty of type UIElement instead of type TextBlock. This has the additional advantage of not restricting the display of content to just a TextBlock. If you really do want to restrict it to just a TextBlock, you can use a validation callback.

public UIElement Content { get { ...
public static readonly DependencyProperty ContentProperty = ...

Solution 2

Just got a non-ideal workaround from a colleague of mine. It involves declaring the Caption property as a resource like:

<Page.Resources>
    <TextBlock x:Key="test" Text="Caption text" FontSize="18" Foreground="White" />
</Page.Resources>

<l:CustomPanel Caption="{StaticResource test}" />

I'd still like to know why I can't use the two previous options, so if anyone knows please answer. :)

Share:
10,313
Willy
Author by

Willy

:D

Updated on June 05, 2022

Comments

  • Willy
    Willy almost 2 years
    private TextBlock _caption = new TextBlock();
    
    public TextBlock Caption  
    {  
        get { return _caption; }  
        set { _caption = value; }  
    }
    
    <l:CustomPanel>  
        <l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />  
    </l:CustomPanel>
    

    Gives me the following error:
    Cannot set properties on property elements.

    If I use:

    <l:CustomPanel>  
        <l:CustomPanel.Caption>
            <TextBlock Text="Caption text" FontSize="18" Foreground="White" /> 
        </l:CustomPanel.Caption>
    </l:CustomPanel>
    

    My TextBlock shows up fine but it's nested inside another TextBlock like so, it even seems to add itself outside of the Caption property:

    <l:CustomPanel>  
        <l:CustomPanel.Caption>
            <TextBlock>
                 <InlineUIContainer>
                     <TextBlock Text="Caption text" FontSize="18" Foreground="White" /> 
                 </InlineUIContainer>
            </TextBlock>
        </l:CustomPanel.Caption>
    
        <TextBlock>
             <InlineUIContainer>
                 <TextBlock Text="Caption text" FontSize="18" Foreground="White" /> 
             </InlineUIContainer>
        </TextBlock>
    </l:CustomPanel>
    

    As you might have already guessed, what i'd like my code to do is to set my Caption property from XAML on a custom panel, if this is possible.

    I've also tried the same code with a DependencyProperty to no avail.

    So, anyone that can help me with this problem?

  • Willy
    Willy about 14 years
    Thx Ray, that worked :) Although I didn't need it anymore, I might need it in the future though, so thank you for the clear explanation.
  • Glenn Maynard
    Glenn Maynard over 7 years
    Except, how are you supposed to say <my.element xml:space="preserve">? Somebody didn't think this through, and blindly applied this to all attributes, even ones that don't belong to them.