Home > Software engineering >  WPF multiline TAB Controls with rearranging Tabitems
WPF multiline TAB Controls with rearranging Tabitems

Time:01-13

I am using tab controls with tab items in xaml wpf

Tab items move to next line and Rearrange, when tab items space exceeds horizontal width of tab controls. Even the space between tabs increase more than margin i have set. (attached image)

when i select row tab item whole row will move down and below row will move up

Help to maintain uniform space between tabs and move tabs to next row if space is less to have all tabs in same row

<TabControl Name="tabCtrlControl" Visibility="Visible" BorderBrush="#FFE3E3E2" 
          BorderThickness="0" Padding="0" TabStripPlacement="Top" Focusable="False" SelectedIndex="0">
            <TabControl.Resources>
                <Style TargetType="{x:Type TabItem}">
                    <Setter Property="BorderBrush" Value="#FFE3E3E2"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type TabItem}">
                                <Grid SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="auto"/>
                                        <RowDefinition Height="*" />
                                    </Grid.RowDefinitions>
                                    <ItemsControl>
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <WrapPanel Name="HeaderPanel" ZIndex="1" Grid.Column="0" Grid.Row="0" Margin="2,2,2,0" IsItemsHost="true" />
                                            </ItemsPanelTemplate>
                                        </ItemsControl.ItemsPanel>
                                    </ItemsControl>
                                    <Border x:Name="Bd" BorderBrush="Black" BorderThickness="2" Margin="2,0,0,0" Grid.Row="0" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                                        <ContentPresenter x:Name="Content" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                                    </Border>
                                     </Grid>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsSelected" Value="True">
                                        <Setter Property="Background" TargetName="Bd" Value="#FFF9F9F9"/>
                                        <Setter Property="Foreground" Value="#FF191919"/>
                                    </Trigger>
                                    <Trigger Property="IsSelected" Value="False">
                                        <Setter Property="Background" TargetName="Bd" Value="#FF191919"/>
                                        <Setter Property="Foreground" Value="#FFe3e3e2"/>
                                    </Trigger>
                                    <Trigger Property="IsEnabled" Value="false">
                                        <Setter Property="Background" TargetName="Bd" Value="#FFb3b3b3"/>
                                        <Setter Property="Foreground" Value="#FFe3e3e2"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TabControl.Resources>
            <TabItem Name="tabItem1" HorizontalAlignment="Right" FontSize="14" Width="90" Height="Auto" MinHeight="30" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.FlowModeText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab1Frame" Source="FlowMode.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480"  FocusVisualStyle="{x:Null}" />
                </Grid>
            </TabItem>
            <TabItem Name="tabItem2" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.StageOverrideText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab2Frame" Source="StageOverride.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem3" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.ColourOverrideText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab3Frame" Source="ColourOverride.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480"  FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem4" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.IsDigitalOutputAvailable, Converter={StaticResource BooleanToVisibilityConverter}}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.DigitalOutputText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab4Frame" Source="DigitalOutput.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem5" Visibility="{Binding Path=IsAutomaticAdjustmentOfInteriorZoneEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="185" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.InteriorZoneSensorStatusText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab5Frame" Source="InteriorZoneSensorStatusMonitor.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem6" Visibility="{Binding Path=ShowIndividualControlTab, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="128" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.IndividualControlText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab6Frame" Source="IndividualControl.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem7" Visibility="{Binding Path=ShowAdvancedControlTab, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="135" Height="Auto" MinHeight="30" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.AdvancedControlText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab7Frame" Source="AdvancedControl.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
        </TabControl>

enter image description here

CodePudding user response:

I suggest you try re templating your tabcontrols and replace the tabpanel with a horizontal scrolling panel instead.

Something like ( and I mean roughly rather than just cut and paste ).

<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto" >
    <StackPanel Orientation="Horizontal" 
                             IsItemsHost="True"
                             x:Name="HeaderPanel"
      />
</ScrollViewer>

Replacing

      <TabPanel x:Name="HeaderPanel"
                Grid.Row="0"
                Panel.ZIndex="1"
                Margin="0,0,4,-1"
                IsItemsHost="True"
                KeyboardNavigation.TabIndex="1"
                Background="Transparent" />

In the template here:

https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/tabcontrol-styles-and-templates?view=netframeworkdesktop-4.8

If you then want to avoid the track and slider and just have the repeat buttons and arrows at either end then you need to also re template the scrollviewer.

You can see that done in an answer on msdn here:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ed5dcfd-0f81-4451-bc30-954721086965/multiple-tabpanel-tabitem-show-in-schrollviewer-using-style?forum=wpf

CodePudding user response:

Similar question was already asked on MSDN almost 17 years ago: https://social.msdn.microsoft.com/Forums/vstudio/en-US/277bb9d9-d082-4ca8-929c-65ede8aead2a/how-to-prevent-tabcontrol-from-doing-multi-rows?forum=wpf

What you're may be looking for is (their code adjusted to your tabs content):

<TabControl Grid.Row="5" TabStripPlacement="Top" 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>
            <Setter Property="Width" Value="22" />
            <!--Setter Property="Visibility" Value="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/ -->
        </Style>
        <ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
            <Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="0"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Border Grid.Row="1" Grid.Column="0" 
                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 TargetType="{x:Type ScrollViewer}">
                                        <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="*"/>
                                                <ColumnDefinition Width="Auto"/>
                                                <ColumnDefinition Width="Auto"/>
                                            </Grid.ColumnDefinitions>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto"/>
                                            </Grid.RowDefinitions>
                                            <ScrollContentPresenter Grid.Column="0" Content="{TemplateBinding ScrollViewer.Content}" />
                                            <RepeatButton Grid.Column="1" Content="&lt;" Command="ScrollBar.LineLeftCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}"/>
                                            <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>
        </ControlTemplate>
    </TabControl.Resources>
            <TabItem Name="tabItem1" HorizontalAlignment="Right" FontSize="14" Width="90" Height="Auto" MinHeight="30" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.FlowModeText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab1Frame" Source="FlowMode.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480"  FocusVisualStyle="{x:Null}" />
                </Grid>
            </TabItem>
            <TabItem Name="tabItem2" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.StageOverrideText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab2Frame" Source="StageOverride.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem3" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.ColourOverrideText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab3Frame" Source="ColourOverride.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480"  FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem4" HorizontalAlignment="Right" FontSize="14" Width="108" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.IsDigitalOutputAvailable, Converter={StaticResource BooleanToVisibilityConverter}}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.DigitalOutputText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab4Frame" Source="DigitalOutput.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem5" Visibility="{Binding Path=IsAutomaticAdjustmentOfInteriorZoneEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="185" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.InteriorZoneSensorStatusText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab5Frame" Source="InteriorZoneSensorStatusMonitor.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem6" Visibility="{Binding Path=ShowIndividualControlTab, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="128" MinHeight="30" Height="Auto" FocusVisualStyle="{x:Null}" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.IndividualControlText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab6Frame" Source="IndividualControl.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
            <TabItem Name="tabItem7" Visibility="{Binding Path=ShowAdvancedControlTab, Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalAlignment="Right" FontSize="14" Width="135" Height="Auto" MinHeight="30" IsEnabled="{Binding Path=SysModeRunning, Converter={StaticResource InverseBoolConverter}}" FocusVisualStyle="{x:Null}">
                <TabItem.Header>
                    <TextBlock TextWrapping="WrapWithOverflow" Text="{x:Static stringtranslation:Resources.AdvancedControlText}"/>
                </TabItem.Header>
                <Grid Background="Transparent">
                    <Frame Name="tab7Frame" Source="AdvancedControl.xaml" NavigationUIVisibility="Hidden" Background="#FFF8FCFE" Height="480" FocusVisualStyle="{x:Null}"/>
                </Grid>
            </TabItem>
</TabControl>

They claim it is possible to display the navigation buttons only when needed by setting the visibility of those depending on ComputedHorizontalScrollBarVisibility. I couldn't make it work, hence the comment.

Nevertheless, check the original thread on MSDN for more information.

  • Related