none
HeaderedContentControl template

    Question

  • Hi!

    I am trying to create a control template for a TabControl and its TabItems

    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate>
              <Grid>
              <Rectangle Fill="{StaticResource BackgroundGradientBrush}"/>
                <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}"/>
              </Grid>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
        <Setter Property="HeaderTemplate">
          <Setter.Value>
            <DataTemplate>
                <ContentPresenter Content="{TemplateBinding Property=HeaderedContentControl.Header}"/>
            </DataTemplate>
          </Setter.Value>
        </Setter>
      </Style>

    The first part  concerning the TabItem works but the content of the Header (I inserted an Image) does not work it doesn't show the Image while it shows when I remove the template...

    Am I overlooking something? I guess my DataTemplate or TemplateBinding is wrong...

    Thanks

    Saturday, February 18, 2006 10:25 PM

Answers

  • Hi Erno,

    I am guessing that you want to change the way the data in the header and content are displayed and not the way the TabItem control itself works, is this correct? If this is the case, you can do it by setting the HeaderTemplate and ContentTemplate properties of TabItem, as you can see in the following markup:

     <Style TargetType="{x:Type TabItem}">
      <Setter Property="ContentTemplate">
       <Setter.Value>
        <DataTemplate>
         <Grid>
          <Rectangle Fill="{StaticResource BackgroundGradientBrush}"/>
          <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}"/>
         </Grid>
        </DataTemplate>
       </Setter.Value>
      </Setter>
      <Setter Property="HeaderTemplate">
       <Setter.Value>
        <DataTemplate>
         <Border BorderBrush="Black" BorderThickness="2">
          <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
         </Border>
        </DataTemplate>
       </Setter.Value>
      </Setter>
     </Style>

    Notice that in your markup samples you are templating the whole TabItem itself, instead of the Content. The default template for TabItem has a lot of information that you are loosing by redefining it, such as where the Content and Header data is placed, which is why you are not seeing your header data in your first sample. If you really want to redefine the template for the TabItem I recommend using Sparkle (I mean, Expression Interactive Designer) where you can start from the default template and change only the things you need. Redefining it from scratch without looking at the existing template is a bit of a challenge.

    In the DataTemplate for the HeaderTemplate I am template-binding to the Content property, and not to Header. The reason is that the DataTemplate you are defining for the Header is being applied to a ContentPresenter in the template of TabItem. This ContentPresenter already has a Content property template-bound to the Header of the TabItem. In other words, when you define a HeaderTemplate, the Content that is passed to it is the Header data itself. When you define a ContentTemplate, the Content passed is the data in the Content data.

    If all you want is to show the data you put in the header (and not display a border around it like in my markup) you don't even need to set the HeaderTemplate. The default HeaderTemplate shows the data you set the Header to. Try commenting the setter for HeaderTemplate and you will see that the Header data is still there.

    If you want to play with a sample that contains this markup, you can find it here: http://www.beacosta.com/Forum/HeaderedContentControlSample.zip

    Let me know if this helps.

    Bea

     

    Sunday, February 19, 2006 8:41 PM

All replies

  • Content presenter uses a set of properties to control the presentation, not just Content.  Look at the ContentSource property:

    This property makes sense only in a style. It cannot be set directly. When a style contains a ContentPresenter with ContentSource="Abc", its Content, ContentTemplate, and ContentTemplateSelector properties are automatically aliased to Abc, AbcContentTemplate, and AbcContentTemplateSelector, respectively.

    You can use this to avoid having to do so many explicit bindings.

    You should also set the target type of the control template.

    Saturday, February 18, 2006 10:57 PM
  • Michael,

    I am sorry, I don't understand what you're saying.

    I recognize and I think I understand the part about the Abc thing form the MSDN.

    However, I do not understand why and how this should help me.

    As far as I know I do not use an explicit binding.
    The code I presented is a template and has a targettype (TabItem)

    Could you please elaborate or show me how to fix my Xaml?

    Thanks!

    Saturday, February 18, 2006 11:47 PM
  • I have changed my template to this:

    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate>
              <Grid>
              <Rectangle Fill="{StaticResource BackgroundGradientBrush}"/>
                <ContentPresenter Margin="10,5,10,5" Content="{TemplateBinding Property=TabItem.Header}"/>
              </Grid>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>

    This sort of does what I want but I do not understand it because I thought that I needed to specify the HeaderTemplate because now I mess with the Content which is actually the area that contains the controls on the Tab page. Apparently not... I don't get it...

    Could someone explain to me what is going on?

    Cheers

    Sunday, February 19, 2006 12:42 AM
  • Hi Erno,

    I am guessing that you want to change the way the data in the header and content are displayed and not the way the TabItem control itself works, is this correct? If this is the case, you can do it by setting the HeaderTemplate and ContentTemplate properties of TabItem, as you can see in the following markup:

     <Style TargetType="{x:Type TabItem}">
      <Setter Property="ContentTemplate">
       <Setter.Value>
        <DataTemplate>
         <Grid>
          <Rectangle Fill="{StaticResource BackgroundGradientBrush}"/>
          <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}"/>
         </Grid>
        </DataTemplate>
       </Setter.Value>
      </Setter>
      <Setter Property="HeaderTemplate">
       <Setter.Value>
        <DataTemplate>
         <Border BorderBrush="Black" BorderThickness="2">
          <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
         </Border>
        </DataTemplate>
       </Setter.Value>
      </Setter>
     </Style>

    Notice that in your markup samples you are templating the whole TabItem itself, instead of the Content. The default template for TabItem has a lot of information that you are loosing by redefining it, such as where the Content and Header data is placed, which is why you are not seeing your header data in your first sample. If you really want to redefine the template for the TabItem I recommend using Sparkle (I mean, Expression Interactive Designer) where you can start from the default template and change only the things you need. Redefining it from scratch without looking at the existing template is a bit of a challenge.

    In the DataTemplate for the HeaderTemplate I am template-binding to the Content property, and not to Header. The reason is that the DataTemplate you are defining for the Header is being applied to a ContentPresenter in the template of TabItem. This ContentPresenter already has a Content property template-bound to the Header of the TabItem. In other words, when you define a HeaderTemplate, the Content that is passed to it is the Header data itself. When you define a ContentTemplate, the Content passed is the data in the Content data.

    If all you want is to show the data you put in the header (and not display a border around it like in my markup) you don't even need to set the HeaderTemplate. The default HeaderTemplate shows the data you set the Header to. Try commenting the setter for HeaderTemplate and you will see that the Header data is still there.

    If you want to play with a sample that contains this markup, you can find it here: http://www.beacosta.com/Forum/HeaderedContentControlSample.zip

    Let me know if this helps.

    Bea

     

    Sunday, February 19, 2006 8:41 PM
  • Hi Bea,

    Yes, this is what I was looking for! Thank you so much!

    By the way: the reason that I wanted to do this is that when I switch my desktop to use the XP theme my tabs do not look good anymore (some nasty artifacts at the botom of the headers and ugly yellow top edges)

    Thanks again!

    Monday, February 20, 2006 9:15 AM
  • Oh, btw the reason for me not using Sparkle (oops I mean EID) is that it kills my code because I'm using usercontrols.

    Of course I can use it with a dummy app to find out what is going on... This time I really wanted to understand what I was doing...

     

    Thanks again!

    Monday, February 20, 2006 9:21 AM