"Styling" the content of a ContentControl

People have occasionally asked about using a Style to set the content of a control. For example, suppose you want all of your buttons in an application to have the same content. You can do something like this (As usual, this doesn’t make sense for a real world scenario, but it gives a simple example to explain concepts which can be applied to more meaningful situations):

 

    <StackPanel>

      <StackPanel.Resources>

        <!--Create a Style for a button-->

        <Style TargetType="Button">

          <Setter Property="Content">

            <Setter.Value>

              Hello world.

            </Setter.Value>

          </Setter>

        </Style>

      </StackPanel.Resources>

      <!--Create some buttons.-->

      <Button/>

      <Button/>

    </StackPanel>

 

This example creates a style for a Button that sets the Content property to the string, “Hello world.” If you run this, you will see two identical Buttons. However, if you try to set the Content to a UIElement in the Style, you get an exception.

 

    <StackPanel>

      <StackPanel.Resources>

        <!--Create a Style for a button-->

        <!--This throws an exception!-->

        <Style TargetType="Button">

          <Setter Property="Content">

            <Setter.Value>

              <Ellipse Margin="2" Width="10"

                       Height="10" Fill="Blue"/>

            </Setter.Value>

          </Setter>

        </Style>

      </StackPanel.Resources>

      <!--Create some buttons.-->

      <Button/>

      <Button/>

    </StackPanel>

 

This throws an exception because the value of Setter.Value is shared and objects that inherit from UIElement cannot have more than one parent. (Even if you create only one Button, you still get an exception.) Instead of setting the Content property, you should set the ContentTemplate property and define a DataTemplate that contains the UIElement.

 

    <StackPanel>

      <StackPanel.Resources>

        <!--Create a Style for a button-->

        <Style TargetType="Button">

          <Setter Property="ContentTemplate" >

        <Setter.Value>

              <DataTemplate>

                  <Ellipse Margin="2" Width="10"

                           Height="10" Fill="SlateGray"/>

              </DataTemplate>

            </Setter.Value>

          </Setter>

        </Style>

     </StackPanel.Resources>

      <!--Create some buttons.-->

      <Button/>

      <Button/>

    </StackPanel>

 

Now you have two buttons, each containing an Ellipse. When the Ellipse is in a DataTemplate, the DataTemplate creates a new Ellipse for each control, so each Button has its own Ellipse.

 

That still isn’t all that interesting, though. What if you want all your buttons to contain an Ellipse and some other kind of content? You can add a ContentPresenter to the DataTemplate and then add content to a button just as you would normally. The following example creates two buttons that have an Ellipse to the left of the buttons’ specific content.

 

    <StackPanel>

      <StackPanel.Resources>

        <!--Create a Style for a button.-->

        <Style TargetType="Button">

          <Setter Property="ContentTemplate" >

            <Setter.Value>

              <DataTemplate>

                <StackPanel Orientation="Horizontal">

                  <Ellipse Margin="2" Width="10"

                           Height="10" Fill="SlateGray"/>

                  <ContentPresenter Content="{Binding}"/>

                </StackPanel>

               </DataTemplate>

            </Setter.Value>

          </Setter>

        </Style>

      </StackPanel.Resources>

      <!--Create some buttons.-->

      <Button>Hello world.</Button>

      <Button>

        <Rectangle Height="20" Width="20" Fill="Red"/>

      </Button>

    </StackPanel>

 

The moral of the exercise: when you want to change the content of a ContentControl via a Style, set the ContentTemplate property to a DataTemplate instead of setting the Content property directly. The ContentTemplate allows you to define UI that can be shared across many instances of a ContentControl.

 

Carole

About Us


We are the Windows Presentation Foundation SDK writers and editors.