WPF FAQ - Templates

Can I create a ContentTemplate and apply the template to a ContentControl ?

The following code shows how the content template can be created and applied to a content control.

[XAML]
<DataTemplate x:Key='template1'>
  <TextBlock Text='{Binding}' FontSize='12' FontWeight='Bold' TextWrapping='Wrap'></TextBlock>
</DataTemplate>

The above code can be applied as follows.

[XAML]

<Button ContentTemplate='{StaticResource template1}' Content='Click'>
Permalink
How can I get an enumerator to the ContentControl’s logical child elements ?

The LogicalChildren of a ContentControl is of ‘protected-type’ access. You can derive a custom class from it and then expose a public version of the ‘LogicalChildren’ property.

 [C#]

    public class SPanel : StackPanel
    {
        public System.Collections.IEnumerator LogicalChildren {
            get {
                return base.LogicalChildren;
            }
        }
    }
Permalink
How can I define a style for a ContentControl to give it a meaningful appearance in the UI ?

This can be done as follows.

[XAML]

<Style x:Key='ContentCtrl' TargetType='ContentControl'>
    <Setter Property='Background' Value='Red'/>
    <Setter Property='Foreground' Value='Green'/>
    <Setter Property='FontSize' Value='20'/>
    <Setter Property='FontWeight' Value='Bold'/>
    <Setter Property='Template'>
        <Setter.Value>
            <ControlTemplate TargetType='ContentControl'>
                <Grid>
                    <Ellipse Width='{TemplateBinding Width}' Height='{TemplateBinding Width}' Fill='{TemplateBinding Background}'/>
                    <ContentPresenter VerticalAlignment='Center' HorizontalAlignment='Center'/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

...

<ContentControl Width='75' Height='100' Style='{StaticResource ContentCtrl}' Content='Hello'/>
Permalink
How do I create a template programatically?

You can create a template programatically by populating the VisualTree of the template.

[C#]
			DataTemplate template = new DataTemplate();

			template.VisualTree = new FrameworkElementFactory(typeof(Path));

			template.VisualTree.SetBinding(Path.StrokeProperty, new Binding('Stroke'));
			template.VisualTree.SetBinding(Path.StrokeThicknessProperty, new Binding('StrokeThickness'));
			template.VisualTree.SetBinding(Path.FillProperty, new Binding('Interior'));
			template.VisualTree.SetBinding(Path.DataProperty, new Binding('Geometry'));
Permalink
How do I programatically interact with template generated elements?

Getting hold of an element in a ControlTemplate is very easy, as this article explains:

How do I programmatically interact with template-generated elements? Part I

Sample code:

Grid gridInTemplate = (Grid)myButton1.Template.FindName('grid', myButton1);

But, if want to get hold of an item in a DataTemplate (which gets applied for each item in the ItemsControl), then there is more code involved as explained here:

How do I programmatically interact with template-generated elements? Part II

Sample Code:

// Note that the ListBox must have
// IsSynchronizedWithCurrentItem set to True for this to work
ListBoxItem myListBoxItem = (ListBoxItem)(myListBox.ItemContainerGenerator.ContainerFromItem(myListBox.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<contentpresenter>(myListBoxItem);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
TextBlock myTextBlock = (TextBlock)myDataTemplate.FindName('textBlock', myContentPresenter);
</contentpresenter>
Permalink
How can I create a ControlTemplate for a HeaderedItemsControl ?

ControlTemplate can be created for a HeaderedItemsControl as follows.

[XAML]

<!--Define a control template for a HeaderedItemsControl-->
<Style TargetType='HeaderedItemsControl'>
  <Setter Property='Template'>
    <Setter.Value>
      <ControlTemplate TargetType='{x:Type HeaderedItemsControl}'>
        <StackPanel>
          <Grid>
            <Rectangle Fill='{TemplateBinding Background}'/>
            <ContentPresenter ContentSource='Header'/>
          </Grid>
          <Grid>
            <Rectangle Stroke='{TemplateBinding BorderBrush}'/>
            <ItemsPresenter Margin='2,0,0,0'/>
          </Grid>
        </StackPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

...

<HeaderedItemsControl  xmlns:sys='clr-namespace:System;assembly=mscorlib'
                       Header='My colors'
                       Background='SteelBlue'
                       BorderBrush='DarkSlateBlue'>
  <sys:String>Red</sys:String>
  <sys:String>Yellow</sys:String>
  <sys:String>Blue</sys:String>
  <sys:String>Green</sys:String>
</HeaderedItemsControl>
Permalink
How can I create Four Button controls with the contents set to a String, a DateTimeObject, an UIElement and A Panel that contains other UIElement objects?

The example Extensible Application Markup Language (XAML) version could use the <Button.Content> tags around the content of each button, but it is not necessary. The Four buttons can be created as follows.

[XAML]

<!--Create a Button with a string as its content.-->
<Button>This is string content of a Button</Button>

<!--Create a Button with a DateTime object as its content.-->
<Button xmlns:sys='clr-namespace:System;assembly=mscorlib'>
  <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
</Button>

<!--Create a Button with a single UIElement as its content.-->
<Button>
  <Rectangle Height='40' Width='40' Fill='Blue'/>
</Button>

<!--Create a Button with a panel that contains multiple objects 
as its content.-->
<Button>
  <StackPanel>
    <Ellipse Height='40' Width='40' Fill='Blue'/>
    <TextBlock TextAlignment='Center'>Button</TextBlock>
  </StackPanel>
</Button>
Permalink