WPF - Hosting content inside a UserControl

WpfUser Controls

Wpf Problem Overview


I'm trying to create a user control that has a Grid with two rows. the first row for a title and the second one for a content that will be defined outside the user control such as a Button in our example.

Somehow I didn't get it to work.

UserControl1 xaml:

  <Grid Background="LightBlue">
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
</Grid>

MainWindow xaml:

 <Grid>
    <local:UserControl1>
        <Button>Click me</Button>
    </local:UserControl1>
</Grid>

The picture below should explain what's my problem: enter image description here

Wpf Solutions


Solution 1 - Wpf

The following code

<local:UserControl1>
    <Button>Click me</Button>
</local:UserControl1>

Means that you set UserControl1's Content property to be that button. This button simply replaces that UserControls1's markup. So all the things that you have in UserControl1.xaml are not there any more.

EDIT

If you want your UserControl to host some markup that will be set somewhere outside of it, you can add a DependencyProperty to it, for example:

    /// <summary>
    /// Gets or sets additional content for the UserControl
    /// </summary>
    public object AdditionalContent
    {
        get { return (object)GetValue(AdditionalContentProperty); }
        set { SetValue(AdditionalContentProperty, value); }
    }
    public static readonly DependencyProperty AdditionalContentProperty =
        DependencyProperty.Register("AdditionalContent", typeof(object), typeof(UserControl1),
          new PropertyMetadata(null));

And add some element to it's markup to host that additional content. Here's an example extending the markup you provided:

<UserControl ... Name="userControl">
    <Grid Background="LightBlue">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
        <ContentPresenter Content="{Binding AdditionalContent, ElementName=userControl}" />
    </Grid>
</UserControl>

Now you can use it as following:

<local:UserControl1>
    <local:UserControl1.AdditionalContent>
        <Button>Click me</Button>
    </local:UserControl1.AdditionalContent>
</local:UserControl1>

Solution 2 - Wpf

You have to set the ControlTemplate:

<UserControl>
<UserControl.Resources>
    <Style TargetType="{x:Type local:UserControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:UserControl1}">
                    <Grid Background="LightBlue">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="50" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0" Text="Title" FontSize="30" Margin="10,0,0,0"/>
                        <ContentPresenter Grid.Row="1" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
</UserControl>

Solution 3 - Wpf

You can template the user control to add additional visuals like the TextBlock.

<UserControl>
<UserControl.Style>
  <Style TargetType="{x:Type UserControl}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate>              
          <Grid Background="LightBlue"> 
          <Grid.RowDefinitions> 
            <RowDefinition Height="50" /> 
            <RowDefinition Height="*" /> 
          </Grid.RowDefinitions> 
          <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/> 
          <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}"  />
          </Grid> 
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</UserControl.Style>
<Button>
  Click me!
</Button>
</UserControl>

Solution 4 - Wpf

Use template with

> < ContentControl />

Instead of using Content Presenter

So place this:

<UserControl.Style>
        <Style TargetType="{x:Type UserControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type UserControl}" >
                          <Grid Background="LightBlue"> 
                           <Grid.RowDefinitions> 
                            <RowDefinition Height="50" /> 
                            <RowDefinition Height="*" /> 
                          </Grid.RowDefinitions> 
                           <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/> 

                        <ContentControl  Grid.Row="1" Content="{TemplateBinding Content}"  />

                        </Grid> 
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Style>

to your userControl

Solution 5 - Wpf

This is the simple general template for a user control (without using styles or properties to set the content):

<UserControl ...>
   <UserControl.Template>
       <ControlTemplate TargetType="{x:Type UserControl}">
           <!-- control contents here -->
           <ContentPresenter/><!-- outside contents go here -->
           <!-- control contents here -->
       </ControlTemplate>
   </UserControl.Template>
</UserControl>

The <ControlTemplate> represents the user control's XAML duplicated for each control.

The <ContentPresenter> is where the Content gets put when consuming the control.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionErezView Question on Stackoverflow
Solution 1 - WpfEvAlexView Answer on Stackoverflow
Solution 2 - WpfblindmeisView Answer on Stackoverflow
Solution 3 - WpfcodekaizenView Answer on Stackoverflow
Solution 4 - WpfAlamakanambraView Answer on Stackoverflow
Solution 5 - WpfDenis G. LabrecqueView Answer on Stackoverflow