设置 WPF ScrollViewer 的样式,使其看起来像 VS2010 选项卡滚动条

发布于 2024-12-11 17:45:07 字数 8251 浏览 0 评论 0原文

我正在使用 AvalonDock 开发一个供我们的开发人员和 QA 内部使用的工具。我正在开发主题中提供的 VS2010 样式的自定义版本。这种风格的功能不够像 VS2010 那样让我满意。我已经完成了几乎所有的颜色和图像更改,我只是注意到当选项卡数量超出标题区域的容纳范围时,DocumentPane 中的选项卡不会像 VS2010 那样滚动。

由于我的项目中有完整的样式,因此我找到了应用样式的区域。我在 ad:DocumentTabPanel 周围放置了一个 ScrollViewer,认为我可以以某种方式重新设置水平滚动条的样式,以便选项卡的左侧和右侧都有一个箭头。

这可能吗?

VS2010 中溢出滚动的示例

这是我基本修改后的样式,但未对滚动查看器进行任何修改:

    <Style x:Key="{x:Type ad:DocumentPane}" TargetType="{x:Type ad:DocumentPane}">
    <Setter Property="Background" Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DefaultBackgroundBrush}}}"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ad:DocumentPane}" >
                <ControlTemplate.Resources>
                    <ContextMenu x:Key="DocumentsListMenu" StaysOpen="True"  />
                </ControlTemplate.Resources>
                <Border 
                    Background="{TemplateBinding Background}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Border x:Name="PART_Header" 
                            Grid.Row="0" 
                            Focusable="False" 
                            >
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition />
                                    <ColumnDefinition Width="18"/>
                                </Grid.ColumnDefinitions>
                                <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">

                                        <ad:DocumentTabPanel 
                                          x:Name="paneTabsPanel" 
                                          Panel.ZIndex ="1" 
                                          IsItemsHost="True" 
                                          TabItemStyle="{StaticResource CustomDocumentTabItemStyle}"/>

                                </ScrollViewer>
                                <Button x:Name="PART_ShowContextMenuButton" 
                                        Grid.Column="2"
                                        Width="15" Height="15" 
                                        Style="{StaticResource PaneHeaderCommandStyle}">
                                    <Image x:Name="ShowContextMenuIcon" Source="pack://application:,,,/Images/Dev2010/PinMenu.png" Width="13" Height="13" Stretch="None"/>
                                </Button>
                            </Grid>
                        </Border>
                        <Grid Grid.Row="1">
                            <Border 
                                x:Name="topBorder"
                                Height="4"
                                Background="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorder}}}" 
                                CornerRadius="2,2,0,0" 
                                VerticalAlignment="Top"
                                HorizontalAlignment="Stretch"
                                >
                            </Border>
                            <Border
                                x:Name="bottomBorder"
                                Height="4"
                                Background="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorder}}}" 
                                CornerRadius="0,0,2,2" 
                                VerticalAlignment="Bottom"
                                HorizontalAlignment="Stretch"
                                >
                            </Border>
                            <ContentPresenter 
                                    Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem.Content}"
                                    Margin="0,4,0,4"
                                    KeyboardNavigation.TabNavigation="Local"
                                    KeyboardNavigation.DirectionalNavigation="Contained"
                                    KeyboardNavigation.TabIndex="1"
                                    />
                        </Grid>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>                        
                    <Trigger Property="HasItems" Value="False">
                        <Setter Property="Visibility" Value="Hidden"/>
                    </Trigger>
                    <Trigger Property="ShowHeader" Value="False">
                        <Setter Property="Visibility" Value="Collapsed" TargetName="PART_Header" />
                    </Trigger>
                    <!--<DataTrigger Binding="{Binding Path=IsMainDocumentPane, RelativeSource={RelativeSource Self}}" Value="True">
                        <Setter Property="Source" Value="pack://application:,,,/Images/Dev2010/PinDockMenu.png" TargetName="ShowContextMenuIcon"/>
                    </DataTrigger>-->

                                                <Trigger Property="ContainsActiveDocument" Value="True">
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelected}}}" 
                                TargetName="topBorder"/>
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelected}}}" 
                                TargetName="bottomBorder"/>
                                                </Trigger>

                                                <Trigger Property="ContainsActiveContent" Value="True">
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelectedActivated}}}" 
                                TargetName="topBorder"/>
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelectedActivated}}}" 
                                TargetName="bottomBorder"/>
                                                </Trigger>

                                                <EventTrigger RoutedEvent="Window.Loaded">
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <DoubleAnimation
                                    Storyboard.TargetProperty="Opacity"
                                    From="0" To="1"  Duration="0:0:0.200" />
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger>
                                                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I'm using AvalonDock to develop a tool for internal use by our developers and QA. I am working on a custom version of the VS2010 style that is provided in the Themes. The style just didn't function enough like VS2010 for me to be happy with it. I've made almost all the color and image changes and I just noticed that the tabs in the DocumentPane do not scroll like VS2010 when there are more tabs than can fit in the header area.

Since I have the complete style in my project I found the area where the styles are applied. I placed a ScrollViewer around the ad:DocumentTabPanel thinking I could somehow restyle the horizontal scrollbar so that there would be an arrow on the left and on the right of the tabs.

Is this possible?

Example of overflow scrolling in VS2010

Here is the style after my base modifications but without any modification to the scrollviewer:

    <Style x:Key="{x:Type ad:DocumentPane}" TargetType="{x:Type ad:DocumentPane}">
    <Setter Property="Background" Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DefaultBackgroundBrush}}}"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ad:DocumentPane}" >
                <ControlTemplate.Resources>
                    <ContextMenu x:Key="DocumentsListMenu" StaysOpen="True"  />
                </ControlTemplate.Resources>
                <Border 
                    Background="{TemplateBinding Background}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Border x:Name="PART_Header" 
                            Grid.Row="0" 
                            Focusable="False" 
                            >
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition />
                                    <ColumnDefinition Width="18"/>
                                </Grid.ColumnDefinitions>
                                <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">

                                        <ad:DocumentTabPanel 
                                          x:Name="paneTabsPanel" 
                                          Panel.ZIndex ="1" 
                                          IsItemsHost="True" 
                                          TabItemStyle="{StaticResource CustomDocumentTabItemStyle}"/>

                                </ScrollViewer>
                                <Button x:Name="PART_ShowContextMenuButton" 
                                        Grid.Column="2"
                                        Width="15" Height="15" 
                                        Style="{StaticResource PaneHeaderCommandStyle}">
                                    <Image x:Name="ShowContextMenuIcon" Source="pack://application:,,,/Images/Dev2010/PinMenu.png" Width="13" Height="13" Stretch="None"/>
                                </Button>
                            </Grid>
                        </Border>
                        <Grid Grid.Row="1">
                            <Border 
                                x:Name="topBorder"
                                Height="4"
                                Background="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorder}}}" 
                                CornerRadius="2,2,0,0" 
                                VerticalAlignment="Top"
                                HorizontalAlignment="Stretch"
                                >
                            </Border>
                            <Border
                                x:Name="bottomBorder"
                                Height="4"
                                Background="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorder}}}" 
                                CornerRadius="0,0,2,2" 
                                VerticalAlignment="Bottom"
                                HorizontalAlignment="Stretch"
                                >
                            </Border>
                            <ContentPresenter 
                                    Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem.Content}"
                                    Margin="0,4,0,4"
                                    KeyboardNavigation.TabNavigation="Local"
                                    KeyboardNavigation.DirectionalNavigation="Contained"
                                    KeyboardNavigation.TabIndex="1"
                                    />
                        </Grid>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>                        
                    <Trigger Property="HasItems" Value="False">
                        <Setter Property="Visibility" Value="Hidden"/>
                    </Trigger>
                    <Trigger Property="ShowHeader" Value="False">
                        <Setter Property="Visibility" Value="Collapsed" TargetName="PART_Header" />
                    </Trigger>
                    <!--<DataTrigger Binding="{Binding Path=IsMainDocumentPane, RelativeSource={RelativeSource Self}}" Value="True">
                        <Setter Property="Source" Value="pack://application:,,,/Images/Dev2010/PinDockMenu.png" TargetName="ShowContextMenuIcon"/>
                    </DataTrigger>-->

                                                <Trigger Property="ContainsActiveDocument" Value="True">
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelected}}}" 
                                TargetName="topBorder"/>
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelected}}}" 
                                TargetName="bottomBorder"/>
                                                </Trigger>

                                                <Trigger Property="ContainsActiveContent" Value="True">
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelectedActivated}}}" 
                                TargetName="topBorder"/>
                                                    <Setter Property="Background" 
                                Value="{DynamicResource {ComponentResourceKey {x:Type ad:DockingManager}, {x:Static ad:AvalonDockBrushes.DocumentHeaderBorderSelectedActivated}}}" 
                                TargetName="bottomBorder"/>
                                                </Trigger>

                                                <EventTrigger RoutedEvent="Window.Loaded">
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <DoubleAnimation
                                    Storyboard.TargetProperty="Opacity"
                                    From="0" To="1"  Duration="0:0:0.200" />
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger>
                                                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南街女流氓 2024-12-18 17:45:07

我过去做过类似的事情,发现最简单的方法是隐藏 ScrollViewer 的 ScrollBar,并在按下两个 RepeatButton 时手动滚动内容。

我最初开始使用的代码可以在此处找到,但基本思想是覆盖 ScrollViewer 的模板,使其看起来像这样:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <RepeatButton Grid.Column="0" Command="ScrollBar.PageLeftCommand" Content="<" />
    <RepeatButton Grid.Column="2" Command="ScrollBar.PageRightCommand" Content=">" />

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

I did something like this in the past, and found it easiest to hide the ScrollViewer's ScrollBar, and manually scroll the content when two RepeatButtons are pressed.

The code I originally started with can be found here, but the basic idea is to overwrite the ScrollViewer's template to look something like this:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <RepeatButton Grid.Column="0" Command="ScrollBar.PageLeftCommand" Content="<" />
    <RepeatButton Grid.Column="2" Command="ScrollBar.PageRightCommand" Content=">" />

    <ScrollContentPresenter Grid.Column="1" Content="{TemplateBinding ScrollViewer.Content}"/>
</Grid>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文