65.9K
CodeProject 正在变化。 阅读更多。
Home

创建一个类似 Blend 的滚动条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (19投票s)

2009年8月26日

CPOL

5分钟阅读

viewsIcon

67252

downloadIcon

3545

本文展示了如何将滚动条样式化, 使其看起来像 Expression Blend 中的滚动条

引言

我正在构建一个消息应用程序。该应用程序是一个用 C# 编写的 SOA 桌面应用程序,使用了 WPF。在某个时候,我想如果我的应用程序有一个像 Expression Blend 那样基于黑色的主题就好了。我从滚动条开始,这也是我将在本文中讨论的内容:如何样式化滚动条,使其看起来像 Expression Blend 中的滚动条。我样式化了水平和垂直滚动条。可下载的代码还包括一个使用这两个滚动条的列表框的样式(以便滚动条看起来更好 :))。

背景

我猜读者应该对样式和模板有基本的了解。如果读者还要阅读列表框的样式,他们还应该了解一些关于动画的基本知识。

笔刷

示例使用了以下笔刷:  

<SolidColorBrush x:Key="StandardBorderBrush" Color="DarkGray"></SolidColorBrush>
<SolidColorBrush x:Key="StandardBrush" Color="LightGray"></SolidColorBrush>
<SolidColorBrush x:Key="PressedBrush" Color="Gray"></SolidColorBrush>
<SolidColorBrush x:Key="HoverBrush" Color="#fefefe"></SolidColorBrush>
<SolidColorBrush x:Key="GlyphBrush" Color="333333"></SolidColorBrush>

滚动条结构 

正如我们大多数人所知,滚动条不像按钮那样容易样式化。这是因为滚动条大约有 6 个需要处理的组件。您可以在下面的图片中看到它们

为了正确地样式化滚动条,我使用了以下样式:用于一次移动数据一个单位的重复按钮(每个重复按钮一个样式)、用于滑块的样式以及用于透明重复按钮的样式(两者共用一个)。 

最后,滚动条看起来会像下面的图片。左边可以看到整个窗口,右边可以看到滚动条的 3 种状态:正常、悬停和按下。 

垂直滚动条

此滚动条使用 3 行网格定义。向上按钮位于第一行,轨道位于第二行,向下按钮位于第三行。向上按钮的样式可以在下面的标记中看到: 

<Style x:Key="LineButtonUpStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type RepeatButton}">
           <Grid Margin="1" Height="18" >
        <Path Stretch="None"
HorizontalAlignment="Center"
VerticalAlignment="Center" Name="Path"  
Fill="{StaticResource
StandardBrush}"
  Data="M0 0L 8 8 L 4 0 Z"></Path>
         </Grid>
          <ControlTemplate.Triggers>                       
          <Trigger Property="IsMouseOver" Value="true">
  <Setter TargetName="Path" Property="Fill"
Value="{StaticResource HoverBrush}" />
         </Trigger>
     <Trigger Property="IsPressed" Value="true">
     <Setter TargetName="Path" Property="Fill"
Value="{StaticResource PressedBrush}" />
      </Trigger>
       </ControlTemplate.Triggers>
     </ControlTemplate>
     </Setter.Value>
        </Setter>
    </Style> 

如您所见,此按钮显示一个代表三角形的路径元素。使用对齐属性将此三角形放置在按钮的中心。此按钮还有 2 个触发器。当鼠标悬停在按钮上时,三角形会获得一个较亮的笔刷 (HoverBrush),当按钮被按下时,三角形会被赋予一个较暗的笔刷 (PressedBrush)。

向下按钮的样式非常相似。唯一的区别是三角形的方向。这个指向下方。样式可以在下面看到。差异部分为粗体。

<Style x:Key="LineButtonDownStyle"
TargetType="{x:Type RepeatButton}">
         <Setter Property="Focusable"
Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type
RepeatButton}">  
<Grid Margin="1"
Height="18" >
      <Path Stretch="None" HorizontalAlignment="Center"

    VerticalAlignment="Center" Name="Path"  Fill="{StaticResource
StandardBrush}"

   Data="M 0 0 L 4 8 L 8 0 Z"></Path></Grid>
             <ControlTemplate.Triggers>
                   <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="Path" Property="Fill"
                                    Value="{StaticResource HoverBrush}" />
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter TargetName="Path" Property="Fill"
                                    Value="{StaticResource PressedBrush}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

另外两个重复按钮(透明按钮)的样式非常简单。它将按钮的模板设置为一个透明边框。您可以在下面看到此样式

<Style x:Key="ScrollBarPageButtonStyle"
TargetType="{x:Type RepeatButton}">
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Border Background="Transparent"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

滑块的样式可以在下面看到

<Style x:Key="VerticalScrollBarThumbStyle"
TargetType="{x:Type Thumb}">

        <Setter Property="IsTabStop"
Value="False"/>
        <Setter Property="Focusable"
Value="False"/>
     <Setter Property="Margin"
Value="1,0,1,0" />
        <Setter Property="BorderBrush" Value="{StaticResource StandardBorderBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
             <Rectangle Width="8" Name="ellipse"  Stroke="{StaticResource
StandardBorderBrush}"
Fill="{StaticResource StandardBrush}"
           RadiusX="5" RadiusY="5"></Rectangle>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ellipse"
Property="Fill" Value="{StaticResource HoverBrush}"></Setter>
                        </Trigger>
                <Trigger Property="IsDragging" Value="True">
           <Setter TargetName="ellipse"
Property="Fill" Value="{StaticResource PressedBrush}"></Setter>
                        </Trigger>                       
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

从上面的样式可以看出,滑块是一个 8 像素宽的矩形,命名为 ellipse(因为我最初想使用一个椭圆但没有更改它)。滑块也有 2 个触发器。当鼠标悬停在滑块上时,滑块会获得一个较亮的笔刷 (HoverBrush)。当用户拖动滑块时,它会获得一个较暗的笔刷 (PressedBrush)。

为了构建滚动条,需要使用以上所有样式。正如我之前所说,滚动条是一个具有非常微妙的线性渐变背景的三行网格。

<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition MaxHeight="18"/>
                <RowDefinition Height="*"/>
                <RowDefinition MaxHeight="18"/>
            </Grid.RowDefinitions>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
              <GradientStop Offset="0" Color="#4c4c4c"></GradientStop>
              <GradientStop Offset="1" Color="#434343"></GradientStop>
                </LinearGradientBrush>
            </Grid.Background>

在第一行,我们有向上按钮。

<RepeatButton Grid.Row="0" Height="18"
      Style="{StaticResource LineButtonUpStyle}"

Command="ScrollBar.LineUpCommand">  
</RepeatButton>

如您所见,这是一个重复按钮,它使用了之前讨论的 LineButtonUpStyle(带向上指向三角形的样式)。

在第二行,我们有滚动条的轨道。此轨道必须有一个特殊的名称 (PART_Track)。

<Track Name="PART_Track" Grid.Row="1" IsDirectionReversed="True">
      <Track.DecreaseRepeatButton>
             <RepeatButton Command="ScrollBar.PageUpCommand"
              Style="{StaticResource ScrollBarPageButtonStyle}">
</RepeatButton>
      </Track.DecreaseRepeatButton>
      <Track.Thumb>
            <Thumb Style="{StaticResource VerticalScrollBarThumbStyle}">
            </Thumb>
      </Track.Thumb>
      <Track.IncreaseRepeatButton>
             <RepeatButton Command="ScrollBar.PageDownCommand"
                   Style="{StaticResource ScrollBarPageButtonStyle}">
             </RepeatButton>
       </Track.IncreaseRepeatButton>
</Track>

从上面的 XAML 可以看出,轨道有 3 个部分。顶部的值减小部分,中间的滑块,底部的值增加部分。增加和减小部分使用了一个使用透明样式的重复按钮。滑块使用其先前描述的自己的样式。

在这里我需要提到另一件事:IsDirectionReversed 属性。看起来如果我没有将其设置为 true,滑块会从滚动条的底部开始。

最后,在最后一行,我们有另一个重复按钮(指向下方的三角形按钮)。

<RepeatButton Grid.Row="2" Height="18" Style="{StaticResource LineButtonDownStyle}"
        Command="ScrollBar.LineDownCommand">
</RepeatButton>  

水平滚动条

水平滚动条的结构类似。下面的 XAML 向您展示了模板的标记。

<ControlTemplate x:Key="HorizontalScrollBar"
TargetType="{x:Type ScrollBar}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition MaxWidth="18"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition MaxWidth="18"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                <GradientStop Offset="0" Color="#4c4c4c"></GradientStop>
                    <GradientStop Offset="1" Color="#434343"></GradientStop>
            </LinearGradientBrush>
            </Grid.Background>
            <RepeatButton Grid.Column="0" Width="18"
     Style="{StaticResource LineButtonLeftStyle}"
 Command="ScrollBar.LineLeftCommand">
         </RepeatButton>
            <Track Name="PART_Track"
Grid.Column="1" IsDirectionReversed="False" >
       <Track.DecreaseRepeatButton>
                    <RepeatButton Command="ScrollBar.PageLeftCommand"
                        Style="{StaticResource
ScrollBarPageButtonStyle}">
                    </RepeatButton>
                </Track.DecreaseRepeatButton>
                <Track.Thumb>
                    <Thumb Style="{StaticResource HorizontalScrollBarThumbStyle}">
                    </Thumb>
                </Track.Thumb>
                <Track.IncreaseRepeatButton>
                    <RepeatButton Command="ScrollBar.PageRightCommand"
                        Style="{StaticResource ScrollBarPageButtonStyle}">
                    </RepeatButton>
                </Track.IncreaseRepeatButton>
            </Track>
            <RepeatButton Grid.Column="2" Width="18"
 Style="{StaticResource
LineButtonRightStyle}"
                Command="ScrollBar.LineRightCommand">
            </RepeatButton>
        </Grid>
    </ControlTemplate>

如您所见,这次我们有一个 3 列网格。第一列包含向左滚动的重复按钮,第二列包含轨道,最后一列包含向右滚动的重复按钮。这里使用的样式与垂直滚动条使用的样式几乎相同。触发器完全相同。唯一的区别是三角形的方向(它们分别指向左和右),以及滑块矩形的尺寸。这里最后要提到的一点是,IsDirectionReversed 属性设置为 false。 

滚动条样式 

这两个模板将用于设置滚动条的模板。这是通过样式应用的。您可以在下面看到

<Style TargetType="{x:Type ScrollBar}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>       
<Style.Triggers>
           <Trigger Property="Orientation" Value="Vertical">
               <Setter Property="Width" Value="18"/>
            <Setter Property="Height" Value="Auto" />
           <Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
            </Trigger>
            <Trigger Property="Orientation" Value="Horizontal">
                <Setter Property="Width" Value="Auto"/>
       <Setter Property="Height" Value="18" />
               <Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
           </Trigger>
        </Style.Triggers></Style>

从上面的 XAML 可以看出,如果方向是垂直的,那么垂直滚动条的样式将使用 VerticalScrollBar 模板,如果方向是水平的,则使用 HorizontalScrollBar 模板。最后要提到的一点是,我选择为 4 个滚动按钮(左、右、上、下)使用单独的模板,因为三角形的笔刷需要改变。如果相反,按钮的背景需要改变,这可以通过单个模板(如透明按钮)来完成。

关于列表框样式的一些说明 

另外,请查看列表框的样式,因为它们包含一些非常酷的东西。一种样式化列表框右下角矩形(位于两个滚动条交叉处)的方法。

如果您查看滚动查看器的默认模板,您会注意到这个矩形被命名为“corner”,并使用具有以下键的笔刷

x:Key="{x:Static SystemColors.ControlBrushKey}"

模板添加了一个同名资源来覆盖默认颜色。这利用了 WPF 从元素向外搜索资源的方式。就是这样。希望您喜欢这篇文章。

历史

  • 添加于 2009 年 8 月 26 日星期三 
© . All rights reserved.