Search code examples
c#xamluwpuser-controls

How to create UserControl which support other element inside it in XAML code


I like to insert other FrameworkElements inside my UserControl but if I do so in XAML code the control doesn't work correctly. (I need to make like a Panel/Grid type control). In other words it lost its contents. How to solve this problem? I've found some examples but those one doesn't works in UWP. I want to keep following example very simple to show what I mean and need.

XAML

<!--THE CONTROL-->
<local:TestControl Width="300" Height="300">
    <!--LIKE TO ADD THIS ONE INSIDE THE CONTROL-->
    <TextBlock Text="Some Text"></TextBlock>
</local:TestControl>

XAML FOR CONTROL

<UserControl
    x:Class="MyApp.TestControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"

    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid Background="DarkGray" BorderBrush="Black" BorderThickness="2" CornerRadius="10"></Grid>
</UserControl>

CODE BEHIND

namespace MyApp
{
    public sealed partial class TestControl : UserControl
    {
        public TestControl()
        {
            this.InitializeComponent();
        }
    }
}

Solution

  • Replace the UserControl with a templated control.

    1. Create a class called TestControl that inherits from ContentControl:

      public sealed class TestControl : ContentControl
      {
          public TestControl() => DefaultStyleKey = typeof(TestControl);
      }
      
    2. Create a themes folder in your project and add a ResourceDictinonary called generic.xaml to this folder. The themes/generic.xaml name is important for the framework to be able to find it. In this file, you define a template for your control:

      <Style TargetType="local:TestControl">
          <Setter Property="Template">
              <Setter.Value>
                  <ControlTemplate TargetType="local:TestControl">
                      <Grid Background="DarkGray" BorderBrush="Black" BorderThickness="2" CornerRadius="10">
                          <ContentPresenter />
                      </Grid>
                  </ControlTemplate>
              </Setter.Value>
          </Setter>
      </Style>
      
    3. Create an instance of your control like before:

      <local:TestControl Width="300" Height="300">
          <!--LIKE TO ADD THIS ONE INSIDE THE CONTROL-->
          <TextBlock Text="Some Text"></TextBlock>
      </local:TestControl>
      

    The TextBlock will end up where the ContentPresenter element is in the ControlTemplate.

    Please refer to @Jerry Nixon's MSDN Magazine article for more information about how to create custom controls.