Search code examples
c#wpfmvvmdependency-propertiesuielement

How to implement WPF User Control with UIElement dependency properties?


I have a user control with this code behind:

/// <summary>
/// The text to use for the header.
/// </summary>
public UIElement HeaderText
{
    get { return (UIElement) GetValue(HeaderTextProperty); }
    set { SetValue(HeaderTextProperty, value); }
}

public static DependencyProperty HeaderTextProperty =
    DependencyProperty.Register("HeaderText",
                                typeof(UIElement),
                                typeof(Panel),
                                new PropertyMetadata(null, new PropertyChangedCallback(HeaderTextPropertyChanged)));

private static void HeaderTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as Panel;
    if (control != null)
    {
        control.HeaderText = (UIElement) e.NewValue;
    }
}

And this XAML:

<TextBlock Text="{TemplateBinding local:CustomPanel.HeaderText}" />

And I'm trying to use the user control like this:

<controls:CustomPanel>
    <controls:CustomPanel.HeaderText>
        <TextBlock Text="Foo " />
        <TextBlock Text="{Binding Bar}" />
        <TextBlock Text=" baz." />
    </controls:CustomPanel.HeaderText>
</controls:CustomPanel>

However, what I get is blank/empty text.

I can get it to work if I change UIElement into string in code-behind, but I want to accept both string, TextBlock and practically any UIElement that makes sense for text.

How can I achieve this?


Solution

  • Don't use a TextBlock in your control but a ContentPresenter (and bind the Content), it can host anything. Make the property type object and change the name to Header for consistency.

    (As a side-note: Usually you have additional properties that go along with the Header, namely a HeaderTemplate and a HeaderTemplateSelector. If the ContentPresenter is in a template you can make it bind to all three properties by setting the ContentSource to "Header")