How to use a ContentPresenter inside a UserControl

Th1sD0t picture Th1sD0t · Apr 6, 2016 · Viewed 14.3k times · Source

I'd like to create a UserControl (in this case a square-Button with defined Backgroundcolors) which can host it's own content.

UserControl:

<UserControl x:Class="SGDB.UI.Controls.ModernButton"
         xmlns:local="clr-namespace:SGDB.UI.Controls"
         xmlns:converter="clr-namespace:SGDB.UI.Converter"
         x:Name="_modernButton">
<Button>
    <Button.Resources>
        <converter:EnumToColorConverter x:Key="ColorConverter"/>
    </Button.Resources>
    <Button.Template>
        <ControlTemplate>
            <Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3">
                <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
                    <ContentPresenter/>
                </Grid>
            </Border>
        </ControlTemplate>
    </Button.Template>
</Button>

Now, as you may expect it, if I use this Control inside my MainView everthing works just fine until I define some Content.

Using:

<control:ModernButton Size="200" BackgroundColor="Light">
    TEST
</control:ModernButton>

In this case "TEST" will override the whole Content of the UserControl (the whole Button Template). I guess this happens because The Button inside the UserControl is defined as "Content" itself and it will get overridden when defining new Content.

So the final question is: Is it possible to achieve what I'm looking for? if yes: How? How could I "redirect" the Content I'm defining in my MainView into the self-defined ContentPresenter inside my Button Template instead of the UserControls's ContentPresenter?

If possible I don't want to create a new dp-propery which hosts my Content, e.g.:

<controls:MordernButton Size="200" BackgroundColor="Light">
    <controls:ModernButton.Content>
        I don't want this, if possible
    </controls:ModernButton.Content>
</controls:ModernButton>

Answer

Sriram Sakthivel picture Sriram Sakthivel · Apr 6, 2016

Use the ContentPropertyAttribute to instruct the xaml to set this property instead of the actual Content property.

[ContentProperty("InnerContent")]
public partial class ModernButton : UserControl
{
    public ModernButton()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty InnerContentProperty =
        DependencyProperty.Register("InnerContent", typeof(object), typeof(ModernButton));

    public object InnerContent
    {
        get { return (object)GetValue(InnerContentProperty); }
        set { SetValue(InnerContentProperty, value); }
    }
}

Then in your xaml, Bind the Content Presenter to use InnerContent property instead.

<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/>

This way you can do the following without replacing the actual content.

<control:ModernButton Size="200" BackgroundColor="Light">
    TEST
</control:ModernButton>