WPF-ListBox样式大解析

本文详细探讨了WPF中的ListBox样式,从ListBox的结构到ScrollViewer,再到ScrollBar的定制。通过理解ListBox内部的控件关系,如ItemsControl、Selector、ScrollViewer、ScrollBar等,可以更好地自定义ListBox的外观。通过在 Blend 或 Visual Studio 中创建模板副本,逐步解析每个部分的样式,揭示了ListBox的本质是由底层控件组合而成,为自定义复杂的ListBox样式提供了路径。
摘要由CSDN通过智能技术生成

本文很长,没有耐心,想直接复制的就别看了。(因为确实没有东西可以复制,这里都是“渔”,没有鱼)

ListBox继承自ItemsControl,加入了一个selector对象,可以提供选择(单选、多选功能)。是和显示一个一个的对象。比如文件管理器。

ListView是Listbox上面加入了一个View对象,一般跟GirdView连用,适合显示一条一条的、每一条分好几个栏目的对象。比如百度云的下载管理器。

这里写的是ListBox。

在Blend软件(或者VisualStudio)中为Listbox创建模板副本:

   <SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
        <SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
        <SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
        <SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
        <Style x:Key="ListBoxStyle1" TargetType="{x:Type ListBox}">
            <Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
            <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
            <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
            <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
                            <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </ScrollViewer>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Background" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Background}"/>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Border}"/>
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsGrouping" Value="true"/>
                                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

可见,ListBox是一个border里面嵌套一个ScrollViewer。

在WPF当中,预先设定了两个可以滚动的元素。ScrollBar和ScrollViewer。ScrollView内嵌了横向和纵向的两个ScrollVar,还内嵌了一个Content Container,用来在可以滑动的区域显示其他的东西。所以说,ScrollView是一个封装ScrollBar功能的复合控件。一般不会单独使用ScrllViewer,但是非要这么用也行。单独使用ScrollViewer的时候,是直接可以看到滚动条的:

但是使用ListBox时,元素数量不够的时候就看不到滚动条:

为了能够自定义Listbox样式,先把Listbox改成ListViewer,同样用Blend(或者VisualStudio)创建副本,看到一下代码:

<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="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/>
                <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_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
            </Grid>
        </ControlTemplate>

可见,一个ScrollViewer是一个grid被分成了四行四列:

Row=0、Col=0是内容区域;Row=0、Col=1是纵向的滚轮;Row=1、Col=0是横向滚轮,默认情况下是不可见的,能出现上面这个图是因为把上面代码中 PART_HorizontalScrollBar 的visibility手动设置成了visible,这样看起来直观一点;Row=1、Col=1这块区域被微软很形象的命名成了Corner。

OK,到这儿发现,想要自定义Listbox的样式,得先解决自定义ScrollBar,因为这个自带的Bar实在是太!丑!了!

OK,同样的套路,我们直接在windows里面随便建一个scrollbar:

<ScrollBar>
            
</ScrollBar>

嗯...很真实好吧,确实是一个奇丑无比的scrollbar。同样为其创建模板:

  <SolidColorBrush x:Key="ScrollBar.Static.Background" Color="#F0F0F0"/>
        <SolidColorBrush x:Key="ScrollBar.Static.Border" Color="#F0F0F0"/>
        <SolidColorBrush x:Key="ScrollBar.Pressed.Glyph" Color="#FFFFFF"/>
        <SolidColorBrush x:Key="ScrollBar.MouseOver.Glyph" Color="#000000"/>
        <SolidColorBrush x:Key="ScrollBar.Disabled.Glyph" Color="#BFBFBF"/>
        <SolidColorBrush x:Key="ScrollBar.Static.Glyph" Color="#606060"/>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="ScrollBar.MouseOver.Background" Color="#DADADA"/>
        <SolidColorBrush x:Key="ScrollBar.MouseOver.Border" Color="#DADADA"/>
        <SolidColorBrush x:Key="ScrollBar.Pressed.Background" Color="#606060"/>
        <SolidColorBrush x:Key="ScrollBar.Pressed.Border" Color="#606060"/>
        <SolidColorBrush x:Key="ScrollBar.Disabled.Background" Color="#F0F0F0"/>
        <SolidColorBrush x:Key="ScrollBar.Disabled.Border" Color="#F0F0F0"/>
        <Style x:Key="ScrollBarButton" TargetType="{x:Type RepeatButton}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Focusable" Value="false"/>
            <Setter Property="IsTabStop" Value="false"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RepeatButton}">
                        <Border x:Name="border" BorderBrush="{StaticResource ScrollBar.Static.Border}" BorderThickness="1" Background="{StaticResource ScrollBar.Static.Background}" SnapsToDevicePixels="true">
                            <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Background" TargetName="border" Value="{StaticResource ScrollBar.MouseOver.Background}"/>
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource ScrollBar.MouseOver.Border}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Background" TargetName="border" Value="{StaticResource ScrollBar.Pressed.Background}"/>
                             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值