使用 Style 和 Template 自定义 WPF DataGrid






4.92/5 (75投票s)
自定义 DataGridRowHeader、DataGridColumnHeader、DataGridCell、DataGridRow 的样式和模板,并更改 DataGrid 中的 ScrollBar 样式
介绍
本文将介绍如何更改数据网格控件的外观。
如何自定义 DataGridColumnHeader、DataGridRow、DataGridCell、DatagridRowHeader 和 DataGrid 的 ScrollViewer 的模板。
在本文中,您将学习如何使用 DataGridRowHeader 样式展开多个 RowDetailTemplate,
如何更改 DataGrid 中的 ScrollBar 样式。
背景
DataGrid 是 WPF 中一个强大的控件。它用于在自定义网格中呈现数据集合。
使用代码
DataGridColumnHeader 样式
默认列标题:
自定义列标题
步骤 1:创建 TargetType=DatagridColumnHeader 的样式
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Height" Value="35" />
<Setter Property="SeparatorBrush" Value="DarkRed" />
<Setter Property="FontWeight" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<!-- Your Template goes here -->
</Setter.Value>
</Setter>
</Style>
步骤 2:创建 TargetType=DatagridColumnHeader 的 ControlTemplate 并将其添加到 Template 中。
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Border x:Name="columnHeaderBorder"
BorderThickness="1"
Padding="3,0,3,0">
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#A5A5A5" />
<GradientStop Offset="1" Color="#4B4B4B" />
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#DEB40A" />
<GradientStop Offset="1" Color="#FF7F00" />
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</Grid>
</ControlTemplate>
使用 LinearGradientBrush 创建边框,通过设置背景颜色来在线性方向上以指定的偏移量设置多种颜色。
LinearGradientBrush 有 2 个属性
- StartPoint:用于在给定点(X 和 Y)填充颜色。
- EndPoint:渐变颜色将在给定终点(X 和 Y)停止填充。
ContentPresenter 保存 DataGridColumn 的内容(数据/标题文本等)。
步骤 3:添加 VisualState 以在鼠标悬停时更改 DataGridColumn 的背景颜色。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="columnHeaderBorder"
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="0" Value="LightYellow" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
VisualStateManager 用于在特定状态更改(正常、鼠标悬停、焦点等)时为控件设置动画。
Storyboard 是一个容器时间线,为其子动画提供对象和属性目标信息。简而言之,所有动画都放置在 Storyboard 中。
Storyboard 具有 **Storyboard.TargetName** 和 **Storyboard.TargetProperty** 附加属性。这些属性用于将指定的动画设置为目标控件的目标属性。
**ColorAnimationUsingKeyFrames** 用于沿一组 KeyFrames 在指定持续时间内为 Color 属性的值设置动画。
在上面的代码中,添加了 ColorAnimationUsingKeyFrames 以将数据网格 **columnHeaderBorder** 控件的 GardientStop[1] 颜色从 **#FF7F00** 更改为 **LightYellow**。
要了解有关动画和 Storyboard 的更多信息,请阅读链接文章。
ColorAnimation 在 Storyboard 中添加,用于在用户鼠标悬停在数据网格列上时更改颜色。
DataGridRow 样式
默认行:
自定义行:
如上图所示,第一个是默认 DataGrid 样式,
第二个是带有行颜色、交替行颜色和鼠标悬停行颜色的自定义样式。
步骤 1:创建 TargetType=DataGridRow 的样式
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="LightYellow" />
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<!-- Row Template goes here -->
</Setter.Value>
</Setter>
</Style>
在上面的代码中,为 DataGridRow 创建了样式,并将 Row Background 属性设置为 **LightYellow**。
步骤 2:为 DataGridRow 创建模板
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#AAFFFFAA" />
<GradientStop Offset="1" Color="#AAFFD455" />
</LinearGradientBrush>
</Border.Background>
<SelectiveScrollingGrid>
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</SelectiveScrollingGrid.ColumnDefinitions>
<SelectiveScrollingGrid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</SelectiveScrollingGrid.RowDefinitions>
<DataGridCellsPresenter Grid.Column="1"
ItemsPanel="{TemplateBinding ItemsPanel}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DataGridDetailsPresenter Grid.Row="1"
Grid.Column="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding
AreRowDetailsFrozen,
ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical},
Converter={x:Static DataGrid.RowDetailsScrollingConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Visibility="{TemplateBinding DetailsVisibility}" />
<DataGridRowHeader Grid.RowSpan="2"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
Visibility="{Binding HeadersVisibility,
ConverterParameter={x:Static DataGridHeadersVisibility.Row},
Converter={x:Static DataGrid.HeadersVisibilityConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</SelectiveScrollingGrid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
在上面的代码中,DataGridRow ControlTemplate 包含 DataGridCellPresenter、DataGridDetailsPresenter 和 DataGridRowHeader。
保持所有这些 Presenter 不变。
我们只需要更改主边框背景颜色,
将 **Border (DGR_Border)** 的背景颜色设置为 LinerGradientBrush,并结合黄色和红色。
因此,网格中的每一行都将以这种背景颜色突出显示。
步骤 3:现在,添加 VisualState 以设置 DataGridRow 的交替行、鼠标悬停行和选中行的背景颜色。
要设置交替行颜色,首先需要将 DataGrid 的 AlternationCount 属性值设置为 2。
<DataGrid Name="dataGrid1"
AlternationCount="2" />
然后,添加 VisualStates(AlternatingRow、MouseOver 和 Selected Row)
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Normal_AlternatingRow">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="0" Value="#AAF0C570" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="0" Value="#AAFF7F00" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal_Selected">
<Storyboard>
<!-- ColorAnimation here same as Normal_AlternatingRow state -->
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<!-- ColorAnimation here same as Normal_AlternatingRow state -->
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
要更改交替行颜色,visualstatemanager 为数据网格行提供了 **Normal_AlternatingRow** 视觉状态。
在上面的代码片段中,添加了三个 VisualState
一个用于 AlternateRow,一个用于 MouseOverRow,一个用于 SelectedRow。
所有都包含 ColorAnimation,它在特定状态更改时更改 **DGR_Border** 控件背景的 GradientStop[0] 和 GradientStop[1] 颜色。
DataGridCell 样式
我创建此样式是为了隐藏默认的数据网格行选中颜色(蓝色)。
因为即使设置了 DataGridRow 的选中颜色,它也不会影响 UI,DataGridCell 的默认样式会将其背景颜色覆盖为默认颜色。
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border x:Name="border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="1"
SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在上面的代码中,我将子元素设置为 Border 控件内的 ContentPresenter,并且 Border 控件放置在 ControlTemplate 根中。
我将 Border 控件的 Background 和 BorderBrush 设置为 **Transparent**,因此 DataGridCell 背景被隐藏。
现在,选中行样式将从 DataGridRow Selected VisualState 应用。
DataGrid RowDetail 模板
步骤 1:为 RowDetails 创建 DataTemplate
<DataTemplate x:Key="RowDetailTemplate">
<Grid x:Name="RowDetailGrid"
Width="470"
Height="Auto"
Margin="5">
<Border HorizontalAlignment="Left"
VerticalAlignment="Top"
CornerRadius="5">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="WhiteSmoke" />
<GradientStop Offset="0.75" Color="#AAFFFFAA" />
<GradientStop Offset="1" Color="#AAFFD455" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Margin="10"
HorizontalAlignment="Center"
FontSize="18"
FontWeight="Black"
Text="Temperature Description" />
<TextBlock Grid.Row="1"
Margin="10"
HorizontalAlignment="Left"
Text="{Binding Description}"
TextWrapping="WrapWithOverflow" />
</Grid>
</Border>
<Border Margin="0 0 8 0" CornerRadius="5">
<Border.Background>
<RadialGradientBrush Center="0.5,1" GradientOrigin="0,1"
Opacity="0.3" RadiusX="0.8" RadiusY="0.8">
<GradientStop Offset="1" Color="#AAFFD455" />
<GradientStop Offset="1" Color="WhiteSmoke" />
</RadialGradientBrush>
</Border.Background>
</Border>
</Grid>
</DataTemplate>
在上面的代码中,两个 Border 控件放置在网格中。
在第一个 Border 中,背景设置为 LinearGradientBrush,数据绑定用于在 RowDetails 面板中显示。
在第二个 Birder 中,背景设置为 RadialGradientBrush,以在详细信息面板顶部放置一个浅色圆圈,如上图所示(RowDetail 面板中“**Temperature Description**”文本周围的颜色)。
下图将描述 RadialGradient 的工作原理(填充颜色)。
步骤 2:创建 ToggleButton 样式以显示/隐藏 RowDetail 面板。
<Style TargetType="ToggleButton">
<Setter Property="Padding" Value="3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<ContentPresenter x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Path x:Name="DefaultPath"
VerticalAlignment="Top"
Data="M0,0 14,7 0,14 Z"
Fill="Gray"
Stretch="Fill" />
<Path x:Name="CheckedPath"
VerticalAlignment="Top"
Data="M0,0 14,0 7,14 Z"
Fill="LightGray"
Stretch="Fill"
Visibility="Collapsed" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
使用 Path 创建了两个形状,一个用于折叠的 RowDetail 面板,一个用于展开的 RowDetail 面板。


Path 用于创建形状或图形对象,如三角形、六边形、椭圆形等。Path 继承自 Shape 类。
您也可以使用 Path 绘制图片。您可以使用 Fill 属性用颜色填充形状。
步骤 3:添加 VisualState 以在 Checked/Unchecked 状态下更改 Path。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0"
Storyboard.TargetName="DefaultPath"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0"
Storyboard.TargetName="CheckedPath"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="CheckedPath"
Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0:0:0.2" Value="#CCAA0000" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
**ObjectAnimationUsingKeyFrames** 动画允许您使用对象而不是原始值作为动画关键帧。
在 ObjectAnimationUsingKeyFrames 动画中只允许 DiscreteObjectkeyframes 关键帧。
在上面的代码中,Expanded/Collapsed Path 的可见性使用 ObjectAnimationUsingKeyFrames 在 **Checked** VisualState 下更改。
在 ToggleButton 的 Checked 状态下,Expanded Path 的颜色使用 ColorAnimationUsingKeyFrames 更改。
**SplineColorKeyFrame** 用于使用样条插值从前一个关键帧的 Color 值动画到其自己的 Value。它在值之间创建可变过渡,由 KeySpline 属性确定。
步骤 4:在 DataGrid 中设置 RowDetailTemplate,并在 RowHeaderTemplate 中添加 ToggleButton。
<DataGrid Name="dataGrid1"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Top"
AlternationCount="2"
MinRowHeight="26"
RowDetailsTemplate="{StaticResource RowDetailTemplate}" >
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<ToggleButton x:Name="RowHeaderToggleButton"
Click="ToggleButton_Click"
Cursor="Hand" />
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
我将 RowDetailTemplate 设置为 **StaticResource**,因为 DataTemplate 是在同一页面中创建的。如果 DataTemplate 或 Style 放置在 ResourceDictionary 中,则必须使用 **DynamicResource** 设置样式。
要在每个行标题中添加 ToggleButton,您需要设置 RowHeaderTemplate,如上所示,ToggleButton 控件设置在 DataGrid RowHeaderTemplate 的 DataTemplate 中。
它将在每个行标题上显示三角形图像(使用 Path 创建),例如

现在,我们需要在点击三角形时或在 ToggleButton 选中时展开 RowDetail。
步骤 5:处理 ToggleButton 点击事件以展开/折叠 RowDetail
首先,您必须在 DataGrid Style 中设置一个属性,以在选中 DataGridRow 时更改 RowDetail 可见性。
<Style TargetType="{x:Type DataGrid}">
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
当选中特定 DataRow 时,这将把 RowDetailVisibilityMode 设置为 Visible。
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
DependencyObject obj = (DependencyObject)e.OriginalSource;
while (!(obj is DataGridRow) && obj != null) obj = VisualTreeHelper.GetParent(obj);
if (obj is DataGridRow)
{
if ((obj as DataGridRow).DetailsVisibility == Visibility.Visible)
{
(obj as DataGridRow).IsSelected = false;
}
else
{
(obj as DataGridRow).IsSelected = true;
}
}
}
在 ToggleButton 的点击事件中,首先使用 **VisualTreeHelper.GetParent** 方法找到选定 ToggleButton 的当前数据网格行。
VisualTreeHelper 用于执行涉及视觉树中节点的任务。
GetParent 方法将返回一个表示视觉对象父级的 **DependencyObject** 值。
现在,根据 ToggleButton 的选中状态和 DataGridRow.DetailsVisibility 设置 DataGridRow 的 **IsSelected** 属性。
步骤 6:添加事件处理程序 - RowDetailsVisibilityChanged 以管理 ToggleButton 的选中状态
<DataGrid Name="dataGrid1"
RowDetailsVisibilityChanged="dataGrid1_RowDetailsVisibilityChanged">
- 在 .CS 文件中创建方法,该方法将从父 DependencyObject 按名称查找 FrameworkElement。
public static FrameworkElement GetTemplateChildByName(DependencyObject parent, string name)
{
int childnum = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childnum; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is FrameworkElement && ((FrameworkElement)child).Name == name)
{
return child as FrameworkElement;
}
else
{
var s = GetTemplateChildByName(child, name);
if (s != null)
return s;
}
}
return null;
}
上述方法将遍历父 DependencyObject 中所有可用的子元素,并按其名称返回子控件。此方法是递归方法,它将自身调用,直到找到子控件或达到最后一个子元素(以先到者为准)。
如果未找到子元素,它将迭代到最后一个子元素并返回 **null** 值。
VisualTreeHelper.GetChild 方法将在视觉树中查找第一个子元素。
**- 创建 DataGrid RowDetailsVisibilityChanged 事件处理程序**
private void dataGrid1_RowDetailsVisibilityChanged(object sender,DataGridRowDetailsEventArgs e)
{
DataGridRow row = e.Row as DataGridRow;
FrameworkElement tb = GetTemplateChildByName(row, "RowHeaderToggleButton");
if (tb != null)
{
if (row.DetailsVisibility == System.Windows.Visibility.Visible)
{
(tb as ToggleButton).IsChecked = true;
}
else
{
(tb as ToggleButton).IsChecked = false;
}
}
}
上述方法将从选定的 DataGridRow Template 中查找 ToggleButton。
如果找到 ToggleButton,则如果 DataGridRow DetailsVisibility=Visible,则将其 **IsChecked** 属性设置为 **true**。
否则,将 **IsChecked** 属性设置为 **false**。
此方法仅用于根据行详细信息可见性更改来更改 Expand/Collapsed **Path(Shape)**。
DataGrid ScrollBar 样式
步骤 1:创建 Repeat Button 样式
<Style x:Key="ScrollButtons" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Name="Border" Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
更改 Repeat Button 模板以删除默认样式。
在 ControlTemplate 中添加 Border 控件并将 Background 设置为 Transparent。现在将 **ContentPresenter** 放置在 Border 中,
ContentPresenter 用于显示 ContentControl 的内容。
当您要自定义控件模板时,请不要忘记将 ContentPresenter 放置在 Template 中,否则您的数据将无法显示。
步骤 2:创建所需的画刷和颜色资源
<Color x:Key="BackgroundColor">#AE2F33</Color>
<Color x:Key="StandardColor">#800000</Color>
<Color x:Key="HoverColor">#AAC64D45</Color>
<Color x:Key="PressedColor">#AA0000</Color>
<Color x:Key="DialogBackgroundColor">#FF666666</Color>
<Color x:Key="ScollBarBackgroundStart">#77C64D45</Color>
<Color x:Key="ScollBarBackgroundEnd">#99C64D45</Color>
<SolidColorBrush x:Key="StandardBrush" Color="{StaticResource StandardColor}" />
<SolidColorBrush x:Key="HoverBrush" Color="{StaticResource HoverColor}" />
<SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}" />
<LinearGradientBrush x:Key="ScollBarBackgroundBrush" StartPoint="0,0" EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="{StaticResource ScollBarBackgroundStart}" />
<GradientStop Offset="1" Color="{StaticResource ScollBarBackgroundEnd}" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
WPF 提供以下不同类型的画刷:
**- SolidColorBrush**:用纯色填充区域。
**- LinearGradientBrush**:用线性渐变填充区域。
**- RadialGradientBrush**:用径向渐变填充区域。焦点定义渐变的起点,圆圈定义渐变的终点。
**- ImageBrush**:用图像填充区域。
**- DrawingBrush**:用 System.Windows.Media.Drawing 填充区域,它可以包含形状、文本、视频、图像或其他绘图。
画刷用于用图形/颜色填充/绘制对象/FrameworkElement。
我为 ScrollBar 的默认、悬停和按下状态创建了画刷。
**步骤 3:创建 ScrollBar Thumb 样式**
<Style x:Key="ScrollThumbs" TargetType="{x:Type Thumb}">
<Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Grid Name="Grid">
<Rectangle Name="Rectangle1"
Width="7"
Height="Auto"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="{TemplateBinding Background}"
RadiusX="4"
RadiusY="4" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
创建了 TargetType=Thumb 的样式,它将通过将 Style 设置为 StaticResource/DynamicResource 来在滚动条中应用 Thumb 样式。
在 ControlTemplate 中添加了 Rectangle 控件,并将 Fill 属性设置为 **{TemplateBinding Background}**,此 TemplateBinding 将从 Control Background 绑定颜色,因此它将 Rectangle Fill 颜色设置为 **BackgroundBrush**(<Setter Property="Background" Value="{StaticResource BackgroundBrush}" />)。
步骤 4:创建 ScrollBar 样式
<Style x:Key="MyScrollBar" TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="{DynamicResource ScollBarBackgroundBrush}" />
<Setter Property="Width" Value="12" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid x:Name="GridRoot"
Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidth}}"
Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="18" />
<RowDefinition Height="0.00001*" />
<RowDefinition MaxHeight="18" />
</Grid.RowDefinitions>
<RepeatButton x:Name="DecreaseRepeat"
Command="ScrollBar.LineUpCommand"
Foreground="{StaticResource StandardBrush}"
Style="{DynamicResource ScrollButtons}">
<Path x:Name="DecreaseArrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="F1 M 3.5,0L 0,7L 7,7L 3.5,0 Z "
Fill="{StaticResource StandardBrush}" />
</RepeatButton>
<Track x:Name="PART_Track"
Grid.Row="1"
Focusable="false"
IsDirectionReversed="true">
<Track.Thumb>
<Thumb x:Name="Thumb"
Background="{DynamicResource ButtonDefaultBrush}"
Style="{DynamicResource ScrollThumbs}" />
</Track.Thumb>
</Track>
<RepeatButton x:Name="IncreaseRepeat"
Grid.Row="2"
Command="ScrollBar.LineDownCommand"
Foreground="{DynamicResource StandardBrush}"
Style="{DynamicResource ScrollButtons}">
<Path x:Name="IncreaseArrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="F1 M 3.5,7L 7,0L 0,0L 3.5,7 Z "
Fill="{StaticResource StandardBrush}" />
</RepeatButton>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在 ScrollBar ControlTemplate 中,添加了两个 Repeat Button(一个用于顶部,一个用于底部)和 Thumb。
对于顶部 RepeatButton,您必须将 Command 设置为 **ScrollBar.LineUpCommand**,并将 Style={DynamicResource ScrollButtons} 设置为先前在 ResourceDictionary 中创建的样式。
使用 Path 创建顶部按钮的形状,并将其放置在 RepeatButton 中。
同样,对于底部 RepeatButton,您必须将 Command 设置为 **ScrollBar.LineDownCommand**,并设置与顶部按钮相同的样式。
创建 Track 并将 Thumb 添加到 **Track.Thumb**。将先前创建的 Thumb 样式设置为 Track.Thumb。
**Track** 表示一个控制基元,用于处理 System.Windows.Controls.Primitives.Thumb 控件的定位和大小调整,该控件用于设置 Primitives.Track.Value。
步骤 5:为 RepeatButton 和 Thumb 添加触发器,以在 MouseOver 和 Pressed 属性更改时更改颜色。
<ControlTemplate.Triggers>
<Trigger SourceName="IncreaseRepeat" Property="IsMouseOver" Value="true">
<Setter TargetName="IncreaseArrow" Property="Fill"
Value="{StaticResource HoverBrush}" />
</Trigger>
<Trigger SourceName="Thumb" Property="IsMouseOver" Value="true">
<Setter TargetName="Thumb" Property="Background"
Value="{StaticResource HoverBrush}" />
</Trigger>
<Trigger SourceName="Thumb" Property="IsDragging" Value="true">
<Setter TargetName="Thumb" Property="Background"
Value="{StaticResource StandardBrush}" />
</Trigger>
</ControlTemplate.Triggers>
在上面的示例中,我为 RepeatButton 创建了 MouseOver 触发器以更改 Fill 属性。
为 Thumb 创建了 2 个触发器,一个用于 MouseOver,一个用于拖动以更改 Thumb Background 属性。
您还可以为其他属性创建触发器(例如:按下、启用等)。
步骤 6:最后,在 DataGrid Template 中设置 ScrollBar 样式。
<ControlTemplate TargetType="{x:Type DataGrid}">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<!--your DataGridColumnHeadersPresenter,ScrollContentPresenter --> <ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
Grid.Row="1"
Grid.ColumnSpan="2"
CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar x:Name="PART_VerticalScrollBar"
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
Style="{DynamicResource MyScrollBar}"
ViewportSize="{TemplateBinding ViewportHeight}" />
<ScrollBar x:Name="PART_HorizontalScrollBar" Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}" />
</ControlTemplate>
<ScrollViewer.Template>
<ItemPresenter />
</ScrollViewer>
</ControlTemplate >
在 DataGrid ControlTemplate 的 ScrollViewer 中添加了两个 ScrollBar。
一个用于垂直滚动,一个用于水平滚动。将 Style 设置为 **{DynamicResource MyScrollBar}**,作为先前创建的滚动条样式。
在这篇文章中,我试图包含所有要点,以完全自定义 DataGrid 样式,从而更改控件的外观。
关注点
在开发过程中,我想到如何显示多个 RowDetails 面板以及在需要时显示/隐藏 RowDetail 面板。
为此,我创建了 ToggleButton 并将其添加到 DataGrid 的 RowHeaderTemplate 中,点击 ToggleButton 时显示 RowDetails,再次点击时隐藏详细信息面板。
我还在这篇文章中实现了与显示/隐藏 RowDetail 面板相关的更改。这是 DataGrid 中的新功能。
历史