Ralf
Ralf

Reputation: 313

How to use ContentPresenter properly in custom WPF UserControl

I want do have a custom UserControl in WPF that basically only puts a caption TextBlock over the actual content (I call it 'AttributePanelItem' here. However, in my current approach the TextBlock is not shown when I direclty assign the Content of the user control.

This is my current XAML for the custom UserControl:

<UserControl x:Class="Common.Controls.AttributePanelItem"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             Name="MyAttributePanelItem"
             d:DesignHeight="100" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="{Binding Caption, ElementName=MyAttributePanelItem}"/>
        <ContentPresenter Grid.Row="1" Content="{Binding InputMask, ElementName=MyAttributePanelItem}" />
    </Grid>
</UserControl>

Here the code behind:

public AttributePanelItem()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(AttributePanelItem), new PropertyMetadata(string.Empty));
        public string Caption
        {
            get { return (string)GetValue(CaptionProperty); }
            set { SetValue(CaptionProperty, value); }
        }

        public static readonly DependencyProperty InputMaskProperty = DependencyProperty.Register("InputMask", typeof(object), typeof(AttributePanelItem), new PropertyMetadata(null));
        public object InputMask
        {
            get { return (object)GetValue(InputMaskProperty); }
            set { SetValue(InputMaskProperty, value); }
        }

This is my current XAML to use the custom UserControl:

<controls:AttributePanel>
            <controls:AttributePanelItem Caption="This caption is shown">
                <controls:AttributePanelItem.InputMask>
                    <TextBox Text="This is my input 1" />
                </controls:AttributePanelItem.InputMask>
            </controls:AttributePanelItem>

            <controls:AttributePanelItem Caption="This caption is not shown">
                <TextBox Text="This is my input 2" />
            </controls:AttributePanelItem>

        </controls:AttributePanel>

In my implementation I use the AttributePanelItem two times. 1. The first usage is working as expected however this is not my favorite. 2. The second usage is how I would like to have it. Unfortunately in this case the caption-TextBlock is not shown.

Would it be possible to make the second case work (with showing the caption TextBlock, but without having to use the )?

I assume I am using the ContentPresenter wrong. However I do not know what I need to change.

Could you please help?

Upvotes: 3

Views: 2535

Answers (1)

redcurry
redcurry

Reputation: 2497

Your use of ContentPresenter is correct, but it should be inside a ContentTemplate. You need to change the UserControl.ContentTemplate to do what you want:

<UserControl
    x:Class="WpfApp1.AttributePanelItem"
    x:Name="MyAttributePanelItem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <UserControl.Style>
        <Style TargetType="UserControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="UserControl">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Row="0" Text="{Binding Caption, ElementName=MyAttributePanelItem}" />
                            <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
         </Style>
    </UserControl.Style>
</UserControl>

Now you'll be able to use your second usage. In fact, you can completely remove InputMask from your UserControl (unless you're using it for something else).

Upvotes: 1

Related Questions