WPF DataGrid自定义样式模板 列表头分隔线 滚动条滑块大小设定 动态数据绑定和更新

本文介绍了如何在WPF中自定义DataGrid的样式,包括表头分隔线、滚动条滑块大小设定,以及如何实现动态数据绑定和更新。通过设置DataGridColumnHeader样式消除不需要的分割线,使用ScrollBar的Track和Thumb属性定制滚动条的外观,并确保固定大小的滑块在数据量变化时仍易于操作。此外,文章还讲解了后台数据绑定到DataGrid的方法,以及如何动态更新表格内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[ 效果图回去放,代码在后面 ]


[ 用到的一些定义如果没有附代码可以随便写个看下效果,因为直接从项目中copy出来的,难免漏掉点点... ]


首先,有几点需要注意:

1.表头样式 [ DataGridColumnHeader ]  

默认带分割线,但每列表头左右分割线都占1px,也就是说假如有三列:

a.  表格最左、右边应该不需要分割线,但默认的有1px

b.  中间需要1px分割线,但默认有2px(相邻两表头分别都有1px)

==>自定义样式使用margin控制,保证表格左右边无分割线,相邻分隔线1px

2.滚动条 [ ScrollBar ]

①结构构成参看:  https://www.cnblogs.com/cody1988/p/wpf_ScrollBar.html

②这里由于项目中表格数据会很多,所以设置垂直方向滚动条的滑块固定尺寸(长30px),避免数据刷出太多导致滚动条太窄点不中,

通过<Track ... ViewportSize="NaN">这个属性设定,这样滑块尺寸就不会通过数据数目来计算确定滑块长度。

③同时,由于固定了滑块大小,界面上表格垂直滚动条可见的情况(VerticalScrollBarVisibility="Visible"),滚动条滚动不可用的时候,滑块会固定在滚动条下方,这个通过设定触发器,保证不可滚动的时候滑块隐藏不可见。

<Setter Property="Visibility" TargetName="PART_Track" Value="Collapsed"/>


代码区域


ps:这里用到Themes主题,可以不管这个,其实真正设定到分割线的,也就只有DataGridHeaderBorder控件,
但自带的属性SeparatorVisibility没有作用,因为默认就是左右都1px宽度的线,不符合我想要的效果,

[ BorderThickness="1,0,1,1" Margin="-1,0" ] 这两个设定的显示效果1px分割,表格左右两边不需显示分割线了。

因此这个可以自己画样式,不用Themes主体。

另外的两个Thumb是用来用户手动调整列宽用的。

<!-- DataGrid表格列表头样式 带分割线 -->
    <Style x:Key="DataGridColumnHeaderStyle2" TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="FontFamily" Value="FZLTZHUNHK"/>
        <Setter Property="Foreground" Value="{DynamicResource Common.Static.Foreground}"/>
        <Setter Property="BorderBrush" Value="{DynamicResource Common.Static.BorderBrush2}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                    <Grid>
                        <Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,0,1,1" Margin="-1,0" Background="{DynamicResource Common.Static.Background2}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}" SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Themes:DataGridHeaderBorder>
                        <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                        <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


设定了多项属性,不明白的可以上msdn上查解释意思

CellStyle设置单元格样式,像文本居左还是居右显示,都该设置在这里,设置RowStyle没有作用!

DataGridColumnHeadersPresenter  表头

ScrollContentPresenter  内容显示区域

ScrollBar x:Name="PART_VerticalScrollBar"  垂直方向滚动条

ScrollBar x:Name="PART_HorizontalScrollBar"   水平方向滚动条

<!--DataGrid主体样式属性-->
    <Style x:Key="DataGridStyleExplorer" TargetType="{x:Type DataGrid}">
        <Setter Property="Foreground" Value="{DynamicResource Common.Static.Foreground}"/>
        <Setter Property="FontFamily" Value="{DynamicResource BaseFontFamily}"/>
        <Setter Property="FontSize" Value="18"/>
        <Setter Property="Background" Value="{StaticResource Common.Static.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource Common.Static.BorderBrush2}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="CanUserSortColumns" Value="False"/>
        <Setter Property="CanUserAddRows" Value="False"/>
        <Setter Property="CanUserReorderColumns" Value="False"/>
        <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
        <!--滚动条释放时才刷新列表-->
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
        <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
        <Setter Property="AutoGenerateColumns" Value="False"/>
        <Setter Property="UseLayoutRounding" Value="True"/>
        <Setter Property="HeadersVisibility" Value="Column"/>
        <Setter Property="SelectionMode" Value="Single"/>
        <Setter Property="HorizontalGridLinesBrush" Value="{DynamicResource Common.Static.BorderBrush.GridLinesBrush}"/>
        <Setter Property="VerticalGridLinesBrush" Value="{DynamicResource Common.Static.BorderBrush.GridLinesBrush}"/>
        <Setter Property="CellStyle">
            <Setter.Value>
                <Style TargetType="DataGridCell">
                    <Setter Property="BorderThickness" Value="0"/>
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Foreground" Value="{DynamicResource Common.Pressed.Foreground2}"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGrid}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                        <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                            <ScrollViewer.Template>
                                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                            <ColumnDefinition Width="Auto"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="*"/>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" 
                                                Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" 
                                                Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <DataGridColumnHeadersPresenter BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,1" x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
                                        <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Background="{StaticResource Common.Static.Background2}" Style="{StaticResource ScrollBarStyle1}"
                                                   Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}" Grid.RowSpan="3"/>
                                        <Grid Grid.Column="1" Grid.Row="2">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                                <ColumnDefinition Width="*"/>
                                            </Grid.ColumnDefinitions>
                                            <ScrollBar x:Name="PART_HorizontalScrollBar"  Background="{StaticResource Common.Static.Background2}" Style="{StaticResource ScrollBarStyle12}" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"   />
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                            </ScrollViewer.Template>
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsGrouping" Value="true"/>
                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
                </MultiTrigger.Conditions>
                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>


做出来的效果是垂直滚动条和水平滚动条按钮都是61*61尺寸的,但由于这两个滚动条在项目中有时候会单独使用,因此做了边框,为了和主体DataGrid表格显示兼容,通过margin设置布局,宽度设置为60,实际61哈,以"Grid x:Name="Bg""里的内容为准。

滚动条构成: 可参看:  https://www.cnblogs.com/cody1988/p/wpf_ScrollBar.html

                     上下按钮 RepeatButton,  中间部分 Track。

                     Track又由: 向上空白区域 Track.DecreaseRepeatButton  RepeatButton

                                         滑块 Track.Thumb  Thumb

                                         向下空白区域 Track.IncreaseRepeatButton      RepeatButton

这里滚动条滑块不采用自动计算尺寸的方式,写了最小长度,保证数据再多用户也可以拖动响应

ViewportSize="NaN"      +       MinHeight="30"

同样,不需要这样设置的,想滑块长度根据显示数据占百分比来设置,去掉上两个设定就可以

<!--垂直滚动条-->
    <Style x:Key="ScrollBarStyle1" TargetType="{x:Type ScrollBar}">
        <Setter Property="Background" Value="{DynamicResource Common.Static.Background2}"/>
        <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="false"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Width" Value="60"/>
        <Setter Property="MinWidth" Value="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ScrollBar}">
                    <Grid x:Name="Bg" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" Margin="0,-1,0,-1">
                        <Grid.RowDefinitions>
                            <RowDefinition  Height="61"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="61"/>
                        </Grid.RowDefinitions>
                        <Border x:Name="scrollbarBorder" Grid.RowSpan="3" BorderBrush="{DynamicResource Common.Static.BorderBrush2}" Background="{TemplateBinding Background}" Width="61" BorderThickness="1" VerticalAlignment="Stretch" />
                        <RepeatButton Grid.Row="0" Command="{x:Static ScrollBar.LineUpCommand}" IsEnabled="{TemplateBinding IsMouseOver}" 
                                    Focusable="False" IsTabStop="False" SnapsToDevicePixels="True"
                                    BorderThickness="0" Padding="0">
                            <Border Width="61" Height="61" Background="{TemplateBinding Background}"
                                    BorderBrush="{Binding BorderBrush, ElementName=scrollbarBorder}"
                                    BorderThickness="{Binding BorderThickness, ElementName=scrollbarBorder}">
                                <Path Data="M 50,0 L 0,50 100,50 z" 
                                        Fill="{DynamicResource Common.Static.Glyph}" Stretch="Fill" 
                                        Height="15" Width="20" 
                                        VerticalAlignment="Center" 
                                        HorizontalAlignment="Center"/>

                            </Border>
                        </RepeatButton>

                        <Track x:Name="PART_Track" IsDirectionReversed="true" IsEnabled="{TemplateBinding IsMouseOver}" Grid.Row="1" ViewportSize="NaN">
                            <Track.DecreaseRepeatButton>
                                <RepeatButton Command="{x:Static ScrollBar.PageUpCommand}" Style="{StaticResource VerticalScrollBarPageButton}"/>
                            </Track.DecreaseRepeatButton>
                            <Track.IncreaseRepeatButton>
                                <RepeatButton Command="{x:Static ScrollBar.PageDownCommand}" Style="{StaticResource VerticalScrollBarPageButton}"/>
                            </Track.IncreaseRepeatButton>
                            <Track.Thumb>
                                <Thumb Style="{StaticResource VScrollBarThumb}" Margin="2,0" MinHeight="30"
                                       BorderBrush="{DynamicResource Common.Static.BorderBrush2}" BorderThickness="1" Background="#FFFFFF"/>
                            </Track.Thumb>
                        </Track>
                        <RepeatButton Grid.Row="2" Command="{x:Static ScrollBar.LineDownCommand}" IsEnabled="{TemplateBinding IsMouseOver}"
                                    Focusable="False" IsTabStop="False" SnapsToDevicePixels="True"
                                    BorderThickness="0" Padding="0">
                            <Border Width="61" Height="61" Background="{TemplateBinding Background}"
                                    BorderBrush="{Binding BorderBrush, ElementName=scrollbarBorder}"
                                    BorderThickness="{Binding BorderThickness, ElementName=scrollbarBorder}">
                                <Path Data="M 50,50 L 0,0 100,0 z" 
                                        Fill="{DynamicResource Common.Static.Glyph}" Stretch="Fill" 
                                        Height="15" Width="20" 
                                        VerticalAlignment="Center" 
                                        HorizontalAlignment="Center"/>
                            </Border>
                        </RepeatButton>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Background" TargetName="Bg" Value="{DynamicResource Common.Disabled.Background}"/>
                            <Setter Property="Visibility" TargetName="PART_Track" Value="Collapsed"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


<!--滚动条空白区域-->
    <Style x:Key="VerticalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

设置差不多了,交给界面使用吧

<DataGrid.Columns>是界面动态绑定的后台数据,绑定的属性是{Binding File_ID} 对应 File_ID。

后台可以通过 dgv_No2.ItemsSource = m_screen_sort_order;实现绑定,这样界面就会自动更新为这个数据带的信息,前提是绑定元 m_screen_sort_order 带了属性 { File_ID, Lot_No, Exp_Date },如果没有也可以后台定义类( get; set; )进行类型转换赋值,这个就多看看网上的资料动态绑定啦!

补充一点:

一般对于存数据的控件,如DataGrid,后台绑定可以用 .ItemsSource,也可以用 .DataContext

一般控件要绑定数据到界面的话,可以用 .DataContext。

设定某个属性的绑定的话,可以 dgv_No2.SetBinding(DataGrid.FontSizeProperty, selected_fontsize); 这种写法

更新界面数据,比如表格增删数据

    a. 可以更新绑定元,然后 .ItemsSource / .DataContext .Clear(); //清空绑定  再重新设定绑定

    b.想要直接更新表格,比如dgv_No2.Items.RemoveAt( index );  //由于有绑定元,不能直接操作界面控件,只能更新绑定元的内容  m_screen_sort_order.RemoveAt( index ),再更新绑定(步骤a.)。

<DataGrid Name="dgv_No2" Width="525" Height="390" IsReadOnly="True" 
          VerticalScrollBarVisibility="Visible" 
          Style="{DynamicResource DataGridStyleExplorer}" ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle2}" ColumnHeaderHeight="40" FontSize="16">
          <DataGrid.Columns>
                   <DataGridTextColumn Width="90" Binding="{Binding File_ID}" Header="No."/>
                   <DataGridTextColumn Width="185" Binding="{Binding Lot_No}" Header="{DynamicResource ID_QC_5}"/>
                   <DataGridTextColumn Width="*" Binding="{Binding Exp_Date}" Header="{DynamicResource ID_QC_6}"/>
          </DataGrid.Columns>
</DataGrid>



有问题或者建议,欢迎提出来哈,写的太仓促了...

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值