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

使用 Style 和 Template 自定义 WPF DataGrid

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (75投票s)

2013年5月2日

CPOL

8分钟阅读

viewsIcon

455717

downloadIcon

23395

自定义 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 中的新功能。

历史


© . All rights reserved.