如何在WPF中使用箭头和点创建标签页眉

问题描述

我正在WPF中动态创建Tabitem。我需要创建带有箭头的标签页眉,以在箭头单击时显示一组标签页眉,如下图所示。

enter image description here

例如如果我有10个标签,则最初应显示3个标签,然后单击下一步按钮,则应显示下3个标签

我发现选项卡标题模板中的选项卡很有用,它可以将多行中的元素显示为每行或多或少相等。

选项卡控件的控件模板的代码如下

                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate targettype="{x:Type TabControl}">
                                        <Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" 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>
                                            <Grid  Grid.Column="0" Background="#f7f7f7">
                                                <Grid HorizontalAlignment="Stretch">
                                                    <Grid.ColumnDeFinitions>
                                                        <ColumnDeFinition></ColumnDeFinition>
                                                        <ColumnDeFinition Width="0"></ColumnDeFinition>
                                                    </Grid.ColumnDeFinitions>
                                                    <TabPanel x:Name="headerPanel"  IsItemsHost="true" Margin="2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" Grid.Column="0"/>
                                                </Grid>
                                            </Grid>
                                            <Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
                                                <Grid>
                                                <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                                </Grid>
                                            </Border>
                                        </Grid>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="TabStripPlacement" Value="Bottom">
                                                <Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
                                                <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                                <Setter Property="Height" TargetName="RowDeFinition0" Value="*"/>
                                                <Setter Property="Height" TargetName="RowDeFinition1" Value="Auto"/>
                                                <Setter Property="Margin" TargetName="headerPanel" Value="2,2"/>
                                            </Trigger>
                                            <Trigger Property="TabStripPlacement" Value="Left">
                                                <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                                                <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                                <Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
                                                <Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
                                                <Setter Property="Width" TargetName="ColumnDeFinition0" Value="Auto"/>
                                                <Setter Property="Width" TargetName="ColumnDeFinition1" Value="*"/>
                                                <Setter Property="Height" TargetName="RowDeFinition0" Value="*"/>
                                                <Setter Property="Height" TargetName="RowDeFinition1" Value="0"/>
                                                <Setter Property="Margin" TargetName="headerPanel" Value="2,2"/>
                                            </Trigger>
                                            <Trigger Property="TabStripPlacement" Value="Right">
                                                <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                                                <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                                <Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
                                                <Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
                                                <Setter Property="Width" TargetName="ColumnDeFinition0" Value="*"/>
                                                <Setter Property="Width" TargetName="ColumnDeFinition1" Value="Auto"/>
                                                <Setter Property="Height" TargetName="RowDeFinition0" Value="*"/>
                                                <Setter Property="Height" TargetName="RowDeFinition1" Value="0"/>
                                                <Setter Property="Margin" TargetName="headerPanel" Value="0,2"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="false">
                                                <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>

现在我得到的输出

enter image description here

如何将多行显示为带有箭头的单行,以移动到下一行。任何代码示例都将有所帮助。

解决方法

基本上,您需要的是一个自定义滚动视图,该视图包装了用于标签页眉的自定义项目面板。

下面的scrollviewer模板将滚动条从项目而不是在其下方向左水平滚动-这有效地将其缩小为两个滚动按钮。另外请注意,PART_VerticalScrollBar在此模板中永久折叠。

<ControlTemplate x:Key="ScrollViewerControlTemplate1" TargetType="{x:Type ScrollViewer}">
    <Grid x:Name="Grid" Background="{TemplateBinding Background}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
        <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="0" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset,Mode=OneWay,RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
        <ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="Collapsed" Value="{Binding VerticalOffset,RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
    </Grid>
</ControlTemplate>

现在,您可以在TabControl模板中,将TabPanel替换为水平StackPanel,并用上面的自定义模板包裹在ScrollViewer中>

...
<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto" Template="{DynamicResource ScrollViewerControlTemplate1}">
    <StackPanel x:Name="headerPanel" Orientation="Horizontal" IsItemsHost="True" Grid.Column="0" Margin="2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
</ScrollViewer>
...

这应该大致产生所需的UI,并且它是配置所需行为的起点(例如,每次单击滚动箭头,您会左右滚动多少……)