locked
How to prevent TabControl from doing multi rows? RRS feed

  • Question

  • Unfortunately the TabControl displays a second line for TabItems which do not fit in

    the first row. Is there an easy way to prevent the TabControl from doing multirows, to

    enable a TabControl look like VisualStudio or IE7?

    Friday, July 14, 2006 12:55 PM

Answers

  • Here. I had some spare time so I whipped together a little sample for ya (see below). Plop that into XAML viewer or something you'll see what I mean. I used EID to reverse engineer the original template, but the important thing to pay attention to is the ScrollViewer and everything in it which replaces the default TabPanel.

    HTH,
    Drew

    <TabControl HorizontalAlignment="Stretch" Margin="104,100,237,83" Width="Auto" x:Name="TabControl" Template="{DynamicResource TabControlControlTemplate1}" IsSynchronizedWithCurrentItem="True" VerticalAlignment="Stretch" Height="Auto">
      <TabControl.Resources>
       <Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
        <Setter Property="Template">
         <Setter.Value>
          <ControlTemplate>
           <Border Background="sc#1, 0.366693377, 0.372125238, 0.6931424">
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
           </Border>
          </ControlTemplate>
         </Setter.Value>
        </Setter>
       </Style>

       <ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
        <Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
         <Grid.ColumnDefinitions>
          <ColumnDefinition x:Name="ColumnDefinition0"/>
          <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
          <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
          <RowDefinition x:Name="RowDefinition1" Height="*"/>
         </Grid.RowDefinitions>
         <Border Grid.Row="1" Grid.Column="0" x:Name="ContentPanel" BorderBrush="#FFD0CEBF" BorderThickness="0,0,1,1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained">
          <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
           <Border Background="{TemplateBinding Background}" x:Name="Border1">
            <ContentPresenter DataContext="{x:Null}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" Content="{TemplateBinding SelectedContent}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentSource="SelectedContent"/>
           </Border>
          </Border>
         </Border>
         <ScrollViewer x:Name="HeaderPanel" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">
          <ScrollViewer.Style>
           <Style TargetType="{x:Type ScrollViewer}">
            <Setter Property="Template">
             <Setter.Value>
              <ControlTemplate>
               <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="25"/>
                 <ColumnDefinition Width="*"/>
                 <ColumnDefinition Width="25"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                 <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <RepeatButton Grid.Column="0" Content="&lt;" Command="ScrollBar.LineLeftCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}"/>
                <ScrollContentPresenter Grid.Column="1" Content="{TemplateBinding ScrollViewer.Content}" />
                <RepeatButton Grid.Column="2" Content="&gt;" Command="ScrollBar.LineRightCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}"/>
               </Grid>
              </ControlTemplate>
             </Setter.Value>
            </Setter>
           </Style>
          </ScrollViewer.Style>
          <StackPanel IsItemsHost="true" Orientation="Horizontal" Background="{x:Null}" KeyboardNavigation.TabIndex="1" />
         </ScrollViewer>
        </Grid>
      </TabControl.Resources>
      <TabItem x:Name="TabItem" Header="TabItem"/>
      <TabItem x:Name="TabItem1" Header="TabItem1"/>
      <TabItem x:Name="TabItem2" Header="TabItem2"/>
      <TabItem x:Name="TabItem3" Header="TabItem3"/>
      <TabItem x:Name="TabItem4" Header="TabItem4"/>
      <TabItem x:Name="TabItem5" Header="TabItem5"/>
     </TabControl>

    Friday, July 14, 2006 9:09 PM
  • Hi,

    How can u modify this so that the scroller scrolls by one whole tab at a time rather than fractions of a tab width.

    Thanks

    Paul

    Sunday, July 16, 2006 6:30 PM

All replies

  • I guess it depends on your definition of easy. :) 

    You would need to modify the ControlTemplate of the TabControl. The default template uses a Grid with a TabPanel in the first row (where the tabs are hosted) and a ContentPresenter in the second row to display the contents of the selected tab.

    You could replace the TabPanel with any Panel type you like. Just thinking out loud... you probably want a Grid with three columns. The center column could be a StackPanel with horizontal alignment and then you'd want to put a ScrollViewer around that. That StackPanel would be the ItemsHost for the tabs. In the left and right columns you would want custom Buttons that raise the scroll commands when they are clicked for scrolling left and right.

    It may take some XAML work to get it to lay out right, but you need to write zero code to accomplish it. 100% designer type work... and that's the beauty of WPF.

    HTH,
    Drew

    Friday, July 14, 2006 5:14 PM
  • Here. I had some spare time so I whipped together a little sample for ya (see below). Plop that into XAML viewer or something you'll see what I mean. I used EID to reverse engineer the original template, but the important thing to pay attention to is the ScrollViewer and everything in it which replaces the default TabPanel.

    HTH,
    Drew

    <TabControl HorizontalAlignment="Stretch" Margin="104,100,237,83" Width="Auto" x:Name="TabControl" Template="{DynamicResource TabControlControlTemplate1}" IsSynchronizedWithCurrentItem="True" VerticalAlignment="Stretch" Height="Auto">
      <TabControl.Resources>
       <Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
        <Setter Property="Template">
         <Setter.Value>
          <ControlTemplate>
           <Border Background="sc#1, 0.366693377, 0.372125238, 0.6931424">
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
           </Border>
          </ControlTemplate>
         </Setter.Value>
        </Setter>
       </Style>

       <ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
        <Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
         <Grid.ColumnDefinitions>
          <ColumnDefinition x:Name="ColumnDefinition0"/>
          <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
          <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
          <RowDefinition x:Name="RowDefinition1" Height="*"/>
         </Grid.RowDefinitions>
         <Border Grid.Row="1" Grid.Column="0" x:Name="ContentPanel" BorderBrush="#FFD0CEBF" BorderThickness="0,0,1,1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained">
          <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
           <Border Background="{TemplateBinding Background}" x:Name="Border1">
            <ContentPresenter DataContext="{x:Null}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" Content="{TemplateBinding SelectedContent}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentSource="SelectedContent"/>
           </Border>
          </Border>
         </Border>
         <ScrollViewer x:Name="HeaderPanel" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">
          <ScrollViewer.Style>
           <Style TargetType="{x:Type ScrollViewer}">
            <Setter Property="Template">
             <Setter.Value>
              <ControlTemplate>
               <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="25"/>
                 <ColumnDefinition Width="*"/>
                 <ColumnDefinition Width="25"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                 <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <RepeatButton Grid.Column="0" Content="&lt;" Command="ScrollBar.LineLeftCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}"/>
                <ScrollContentPresenter Grid.Column="1" Content="{TemplateBinding ScrollViewer.Content}" />
                <RepeatButton Grid.Column="2" Content="&gt;" Command="ScrollBar.LineRightCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}"/>
               </Grid>
              </ControlTemplate>
             </Setter.Value>
            </Setter>
           </Style>
          </ScrollViewer.Style>
          <StackPanel IsItemsHost="true" Orientation="Horizontal" Background="{x:Null}" KeyboardNavigation.TabIndex="1" />
         </ScrollViewer>
        </Grid>
      </TabControl.Resources>
      <TabItem x:Name="TabItem" Header="TabItem"/>
      <TabItem x:Name="TabItem1" Header="TabItem1"/>
      <TabItem x:Name="TabItem2" Header="TabItem2"/>
      <TabItem x:Name="TabItem3" Header="TabItem3"/>
      <TabItem x:Name="TabItem4" Header="TabItem4"/>
      <TabItem x:Name="TabItem5" Header="TabItem5"/>
     </TabControl>

    Friday, July 14, 2006 9:09 PM
  • Hi Drew
    thanks a lot !
    in your Sample, a closing </ControlTemplate> is missing (line 60)

    </Grid>
    </ControlTemplate>
    </TabControl.Resources>

    Sunday, July 16, 2006 1:54 PM
  • Hi,

    How can u modify this so that the scroller scrolls by one whole tab at a time rather than fractions of a tab width.

    Thanks

    Paul

    Sunday, July 16, 2006 6:30 PM
  • Cool, this is exactly my definition of easy.
    Monday, July 17, 2006 10:12 AM
  • Is it possible to remove the scroll "arrows"?

    Thanks in advance,
    Marko Vuksanovic

    Thursday, August 17, 2006 12:19 PM
  • The above code works like a charm. Thank you very much.
    Now our users are asking for an enhancement. The repeat buttons should appear only if there is something to scroll. I mean they should appear only if the tab item headers "overflow", not if they still fit into the available space.
    Is there any solution for this?

    Thanks,
    Michael
    Wednesday, September 19, 2007 4:01 PM
  • Hi,

    you can add this to both ToggleButton:

    Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"

     

    Also, you need to change the HorizontalScrollBarVisibility to "Auto" for the ScrollViewer.

     

     

    Patrice

    Friday, September 28, 2007 1:52 PM
  • Simply ingenious. Thank you very much!

    Michael
    Wednesday, October 10, 2007 12:56 PM
  • Hi.  When I try out the same code, it will run, but VS 2008 says:

    Cannot find the static member 'ContentProperty' on the type 'Control'.  Error at Line 1 Position 2412.  

    It is complaining about:

    <ScrollContentPresenter Grid.Column="1" Content="{TemplateBinding ScrollViewer.Content}" />

    If I replace ScrollViewer.Content with ScrollViewer.Name, it doesn't complain.  I veried that ScrollViewer has a Content property, so why is the IDE complaining?  It wouldnt be a big deal to me, except there is no visual preview while it complains about this..  Help?

    Thanks.

    Sunday, October 21, 2007 4:00 AM
  • Here is an update:

    I got the IDE to recognize the ScrollViewer.Content line be explicitly setting the ControlTemplate TargetType to ScrollViewer:

     <Setter Property="Template">
                                            <Setter.Value>
                                                <ControlTemplate TargetType="{x:Type ScrollViewer}">

    That way it didn't try to treat it as a Control type and was able to infer the available properties.

    I think that is why it works now, but Im pretty new to WPF.
    Sunday, October 21, 2007 5:41 PM
  • Drew - I noticed that in your implementation of scrolling tabs (which works nicely by the way), there is no longer support for keyboard navigation through the tabs.  In the original tab control, the keyboard arrow keys move focus from one tab item to the next.

     

    I've been fiddling around with your control template trying to get the focus to move via the keyboard, but no dice ... any thoughts??

     

    Thursday, April 3, 2008 9:12 PM
  • I'm going to shamelessly bump this up to the top again ... see the above post.

     

    Smile
    Monday, April 28, 2008 9:15 PM
  • Hello,

    I modified this code so that the TabControl's TabItems are displayed on the left vertically up and down.  It seems to be working fairly well...but the TabItem that is selected---the left and right borders are missing on it.  Is there a way to force them to remain?
    (Also the very bottom TabItem...its bottom border is also missing as well.)
    (I also noticed that if your TabItem text is very long it will cause the right border to vanish as well)

    I'm also curious....would it be much more difficult to use a scrollbar that is left of the TabItems  instead of using those repeater buttons?


    Here is the modified code:

    <TabControl HorizontalAlignment="Stretch" Margin="38,23,289,31" Width="Auto" x:Name="TabControl" Template="{DynamicResource TabControlControlTemplate1}" IsSynchronizedWithCurrentItem="True">
      <TabControl.Resources>
       <Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
        <Setter Property="Template">
         <Setter.Value>
          <ControlTemplate>
           <Border Background="sc#1, 0.366693377, 0.372125238, 0.6931424">
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
           </Border>
          </ControlTemplate>
         </Setter.Value>
        </Setter>
       </Style>

       <ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
        <Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
         <Grid.ColumnDefinitions>
          <ColumnDefinition x:Name="ColumnDefinition0"/>
          <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
          <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
          <RowDefinition x:Name="RowDefinition1" Height="*"/>
          <RowDefinition x:Name="RowDefinition2" Height="Auto"/>
         </Grid.RowDefinitions>
         <Border Grid.Row="1" Grid.Column="0" x:Name="ContentPanel" BorderBrush="#FFD0CEBF" BorderThickness="1,1,2,2" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained">
          <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
           <Border Background="{TemplateBinding Background}" x:Name="Border1">
            <ContentPresenter DataContext="{x:Null}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" Content="{TemplateBinding SelectedContent}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentSource="SelectedContent"/>
           </Border>
          </Border>
         </Border>
         <ScrollViewer x:Name="HeaderPanel" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
          <ScrollViewer.Style>
           <Style TargetType="{x:Type ScrollViewer}">
            <Setter Property="Template">
             <Setter.Value>
              <ControlTemplate>
               <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                <Grid.RowDefinitions>
                 <RowDefinition Height="25"/>
                 <RowDefinition Height="*"/>
                 <RowDefinition Height="25"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="100"/>
                 <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <!-- <RepeatButton Grid.Column="0" Grid.Row="0" Content="up" Command="ScrollBar.LineUpCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedVerticalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/> -->
                <RepeatButton Grid.Column="0" Grid.Row="0" Content="up" Command="ScrollBar.LineUpCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" />
                <ScrollContentPresenter Grid.Column="0" Grid.Row="1" Content="{TemplateBinding ScrollViewer.Content}" />
                <RepeatButton Grid.Column="0" Grid.Row="2" Content="down" Command="ScrollBar.LineDownCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" />
                <!-- <RepeatButton Grid.Column="0" Grid.Row="2" Content="down" Command="ScrollBar.LineDownCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedVerticalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/> -->
               </Grid>
              </ControlTemplate>
             </Setter.Value>
            </Setter>
           </Style>
          </ScrollViewer.Style>
          <StackPanel IsItemsHost="true" Orientation="Vertical" Background="{x:Null}" KeyboardNavigation.TabIndex="1" />
         </ScrollViewer>
        </Grid>
        </ControlTemplate>
      </TabControl.Resources>

      <TabItem x:Name="TabItem" Header="TabItem"/>
      <TabItem x:Name="TabItem1" Header="TabItem1"/>
      <TabItem x:Name="TabItem2" Header="TabItem2"/>
      <TabItem x:Name="TabItem3" Header="TabItem3"/>
      <TabItem x:Name="TabItem4" Header="TabItem4"/>
      <TabItem x:Name="TabItem5" Header="TabItem5"/>
        <TabItem x:Name="TabItem6" Header="TabItem6"/>
      <TabItem x:Name="TabItem7" Header="TabItem7"/>
      <TabItem x:Name="TabItem8" Header="TabItem8"/>
      <TabItem x:Name="TabItem9" Header="TabItem9"/>
      <TabItem x:Name="TabItem10" Header="TabItem10"/>
      <TabItem x:Name="TabItem11" Header="TabItem11"/>
        <TabItem x:Name="TabItem12" Header="TabItem12"/>
      <TabItem x:Name="TabItem13" Header="TabItem13"/>
      <TabItem x:Name="TabItem14" Header="TabItem14"/>
      <TabItem x:Name="TabItem15" Header="TabItem15"/>
      <TabItem x:Name="TabItem16" Header="TabItem16"/>
      <TabItem x:Name="TabItem17" Header="TabItem17"/>
     </TabControl>

    none
    • Edited by ashlar Wednesday, August 13, 2008 7:04 PM had 1 more thing to add
    Wednesday, August 13, 2008 6:54 PM
  • How can I use the same thing in SILVERLIGHT?

    I have a same requirement in silverlight. Can you please tell me solution for my problem.

    My requirement is just like below URL iamge: http://i45.tinypic.com/20h2dmw.jpg

    or just like Mozilla or IE 7
    Monday, February 22, 2010 7:31 AM
  • I have taken the silverlight tabcontrol and made the tabitems scrollable.  here is a link to the post

    http://www.dansoltesz.com/post/2010/07/20/Silverlight-tabcontrol-with-scrollable-tabItems.aspx 

    • Proposed as answer by dsoltesz Tuesday, July 20, 2010 2:00 PM
    Tuesday, July 20, 2010 2:00 PM
  • Can we do a vertical scroll tabcontrol like that? 



    Alexsandro_xpt

    Sunday, January 13, 2013 4:04 PM
  • Hello xepaul2

    Have you got to do this feature

    Can u help me?

    Thanks.

    Monday, July 16, 2018 3:51 PM