数据网格控件的使用与定制
1. 列的调整大小和重新排列
当显示自动生成的列时,数据网格(DataGrid)会智能地调整每列的宽度。初始时,每列的宽度刚好能显示当前可见的最大值(如果标题更宽,则以标题宽度为准)。当用户滚动数据时,DataGrid 会尽力保持这种智能的大小调整方式。一旦遇到包含更长数据的行,DataGrid 会自动加宽相应的列以适应数据。不过,这种自动调整大小是单向的,即当离开包含大数据的行时,列不会缩小。
自动调整列宽虽然有趣且通常很有用,但并非总是符合需求。例如,若有一个包含长文本字符串的“Description”列,初始时该列会变得极宽,从而挤压其他列的空间。在列被手动调整大小后,用户滚动数据时它不会再自动放大。
为避免用户面对过宽的列,可通过显式定义列来正确设置列宽。通常,用户可通过拖动列边缘来调整列宽。若要阻止用户调整 DataGrid 中的列宽,可将
CanUserResizeColumns
属性设置为
False
;若要阻止用户调整某一特定列的宽度,可将该列的
CanUserResize
属性设置为
False
;还可通过设置列的
MinWidth
属性来防止用户将列缩得过窄。
此外,DataGrid 允许用户重新排列列。若不希望用户有此功能,可将 DataGrid 的
CanUserReorderColumns
属性或特定列的
CanUserReorder
属性设置为
False
。
2. 定义列
使用自动生成的列可快速创建一个显示所有数据的 DataGrid,但会失去一些控制权,如无法控制列的顺序、宽度、值的格式以及标题文本。更强大的方法是将
AutoGenerateColumns
设置为
False
以关闭自动列生成,然后显式定义所需的列及其设置和顺序。为此,需将正确的列对象填充到
DataGrid.Columns
集合中。
目前,DataGrid 支持三种类型的列,由继承自
DataGridColumn
的三个不同类表示:
-
DataGridTextColumn
:适用于大多数数据类型。值会转换为文本并显示在
TextBlock
中,编辑行时,
TextBlock
会被标准文本框替换。
-
DataGridCheckBoxColumn
:显示一个复选框,自动用于布尔(或可空布尔)值。通常,复选框为只读,编辑行时变为普通复选框。
-
DataGridTemplateColumn
:功能最强大,允许定义数据模板来显示列值,具有与列表控件中使用模板相同的灵活性和功能,可用于显示图像数据或使用专门的 Silverlight 控件。
以下是一个创建包含产品名称和价格两列显示的 DataGrid 示例:
<data:DataGrid x:Name="gridProducts" Margin="5" AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Product" Width="175"
Binding="{Binding ModelName}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Price"
Binding="{Binding UnitCost}"></data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
定义列时,通常需设置三个细节:列顶部显示的标题文本、列的宽度以及获取数据的绑定。DataGrid 的数据绑定方法与大多数其他列表控件不同,其
Binding
方法更灵活,允许在不使用完整模板列的情况下合并值转换器。例如,可使用绑定的
StringFormat
属性将
UnitCost
列格式化为货币值:
<data:DataGridTextColumn Header="Price" Binding=
"{Binding UnitCost, StringFormat='C'}">
</data:DataGridTextColumn>
还可通过修改相应列对象的
Visibility
属性动态显示和隐藏列,通过更改
DisplayIndex
值随时移动列。
3. DataGridCheckBoxColumn
若
Product
类包含布尔属性,
DataGridCheckBoxColumn
会是一个有用的选项。与
DataGridTextColumn
一样,
Binding
属性提取数据,用于设置内部
CheckBox
元素的
IsChecked
属性。此外,
DataGridCheckBoxColumn
还添加了
Content
属性,可在复选框旁边显示可选内容,以及
IsThreeState
属性,用于确定复选框是否支持未确定状态。若使用该列显示可空布尔值的信息,可将
IsThreeState
属性设置为
True
,使用户能点击回到未确定状态。
4. DataGridTemplateColumn
DataGridTemplateColumn
使用数据模板,其工作方式与之前在列表控件中探索的数据模板功能相同。不同之处在于,它允许定义两个模板:一个用于数据显示(
CellTemplate
),一个用于数据编辑(
CellEditingTemplate
)。以下是一个使用模板数据列在网格中放置每个产品缩略图的示例:
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Stretch="None" Source=
"{Binding ProductImagePath, Converter={StaticResource ImagePathConverter}}">
</Image>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
此示例假设已将
ImagePathConverter
值转换器添加到
UserControl.Resources
集合中:
<UserControl.Resources>
<local:ImagePathConverter x:Key="ImagePathConverter"></local:ImagePathConverter>
</UserControl.Resources>
5. 列的格式化和样式设置
可通过设置
Foreground
、
FontFamily
、
FontSize
、
FontStyle
和
FontWeight
属性,以与格式化
TextBlock
元素相同的方式格式化
DataGridTextColumn
。但该列未公开
TextBlock
的所有属性,例如,若要创建显示多行文本的列,无法设置常用的
Wrapping
属性,此时需使用
ElementStyle
属性。
ElementStyle
属性允许创建应用于 DataGrid 单元格内元素的样式。对于简单的
DataGridTextColumn
,该元素是
TextBlock
;对于
DataGridCheckBoxColumn
,是复选框;对于
DataGridTemplateColumn
,则是在数据模板中创建的元素。以下是一个允许列中文本换行的简单样式示例:
<data:DataGridTextColumn Header="Description" Width="400"
Binding="{Binding Description}">
<data:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</data:DataGridTextColumn.ElementStyle>
</data:DataGridTextColumn>
要查看换行后的文本,需扩展行高。由于 DataGrid 无法像 Silverlight 布局容器那样灵活调整自身大小,因此需使用
DataGrid.RowHeight
属性设置固定的行高,该高度适用于所有行。
还可使用
EditingElementStyle
来设置编辑列时使用的元素的样式。
ElementStyle
、
ElementEditingStyle
和列属性可用于格式化特定列中的所有单元格。若要对每列的每个单元格应用格式化设置,最简单的方法是为
DataGrid.RowStyle
属性配置样式。此外,DataGrid 还公开了一组额外的属性,用于格式化网格的其他部分,如下表所示:
| 属性 | 样式应用于… |
| ---- | ---- |
| ColumnHeaderStyle | 网格顶部用于列标题的
TextBlock
|
| RowHeaderStyle | 用于行标题的
TextBlock
|
| CornerHeaderStyle | 行标题和列标题之间的角单元格 |
| RowStyle | 普通行(未通过列的
ElementStyle
属性专门定制的列中的行)使用的
TextBlock
|
6. 控制列宽
设置列的初始大小时,可设置其
Width
属性,有三种基本选择:
-
固定大小
:将
Width
属性设置为像素数,如
200
。
-
自动大小
:将
Width
属性设置为以下三个特殊值之一:
SizeToCells
(加宽以匹配最大显示单元格值)、
SizeToHeader
(加宽以匹配标题文本)或
Auto
(加宽以匹配最大显示单元格值或标题,取较大者)。使用
SizeToCells
或
Auto
时,滚动时列可能会加宽。若未设置
Width
属性,列将使用
DataGrid.ColumnWidth
属性的值,默认值为
Auto
。
-
比例大小
:将
Width
属性设置为星号
*
,此方法类似于
Grid
布局容器的比例大小调整。所有固定大小和自动大小的列设置好后,剩余空间将在比例列之间分配。若要让某些列获得更多自由空间,可设置带数字和星号的值,如
2*
的列将获得
*
列两倍的空间。
以下是一个示例,其中一列使用固定宽度,一列使用自动大小,另外两列使用比例大小:
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Model Number" Binding="{Binding ModelNumber}"
Width="100"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Model Name" Width="100"
Binding="{Binding ModelName}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Unit Cost" Width="*" MinWidth="50"
Binding="{Binding UnitCost, StringFormat='C'}"></data:DataGridTextColumn>
<data:DataGridTextColumn Width="2*" MinWidth="50"
Binding="{Binding Description}" Header="Description" >
<data:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</data:DataGridTextColumn.ElementStyle>
</data:DataGridTextColumn>
</data:DataGrid.Columns>
比例大小调整的好处是可创建适应可用空间的网格。只要添加一个比例大小的列,
GridView
就会移除水平滚动条。当调整
GridView
大小时,它会相应地调整列的大小。若将
GridView
调大,比例大小的列将获得所有额外空间;若调小,这些列的空间会逐渐减少,直到达到其
MinWidth
值。若继续缩小,其他列也会从其原始固定或自动大小开始缩小,直到达到其
MinWidth
值;若所有列都达到最小宽度后仍继续缩小,
GridView
会继续将列宽缩小到
MinWidth
设置以下,直到所有列都折叠。
7. 行的格式化
通过设置 DataGrid 列对象的属性,可控制整列的格式。但在许多情况下,标记包含特定数据的行更有用,例如突出显示高价产品或过期发货。可通过处理
DataGrid.LoadingRow
事件以编程方式应用此类格式。
LoadingRow
事件是行格式化的强大工具,它可访问当前行的数据对象,允许执行简单范围检查、比较和更复杂的操作,还提供行的
DataGridRow
对象,可使用不同颜色或字体格式化行。但无法仅格式化该行中的单个单元格,为此需要
DataGridTemplateColumn
和
IValueConverter
。
该事件在每行出现在屏幕上时触发一次。优点是应用程序无需格式化整个网格,仅对当前可见的行触发;缺点是用户滚动网格时,该事件会持续触发,因此不能在
LoadingRow
方法中放置耗时的代码,否则滚动会变慢。
此外,还需考虑虚拟化。为降低内存开销,DataGrid 在滚动数据时会重用相同的
DataGrid
对象来显示新数据,因此要确保将每行恢复到初始状态,以防止将数据加载到已格式化的
DataGridRow
中。
以下是一个示例,将高价物品的背景设置为亮橙色,普通价格物品的背景设置为标准白色:
' Reuse brush objects for efficiency in large data displays.
Private highlightBrush As New SolidColorBrush(Colors.Orange)
Private normalBrush As New SolidColorBrush(Colors.White)
Private Sub gridProducts_LoadingRow(ByVal sender As Object, _
ByVal e As DataGridRowEventArgs)
' Check the data object for this row.
Dim product As Product = CType(e.Row.DataContext, Product)
' Apply the conditional formatting.
If product.UnitCost > 100 Then
e.Row.Background = highlightBrush
Else
' Restore the default white background. This ensures that used,
' formatted DataGrid object are reset to their original appearance.
e.Row.Background = normalBrush
End If
End Sub
另一种基于值的格式化方法是使用
IValueConverter
检查绑定数据并将其转换为其他内容,结合
DataGridTemplateColumn
时此技术尤其强大,可仅格式化包含价格的单元格,而非整行。
8. 行详细信息
DataGrid 支持行详细信息,这是一个可选的单独显示区域,出现在行的列值下方。行详细信息区域有两个优点:一是跨越 DataGrid 的整个宽度,不分割成单独的列,提供更多操作空间;二是可配置为仅在选中行时显示,不使用时可隐藏额外细节。
要创建包含行详细信息的示例,需先设置
DataGrid.RowDetailsTemplate
属性来定义行详细信息区域显示的内容。例如,以下模板包含一个显示完整产品文本并添加边框的
TextBlock
:
<data:DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border>
<Border Margin="10" Padding="10" BorderBrush="SteelBlue" BorderThickness="3"
CornerRadius="5">
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" FontSize="10">
</TextBlock>
</Border>
</Border>
</DataTemplate>
</data:DataGrid.RowDetailsTemplate>
还可在行详细信息区域添加控件以执行各种任务。需注意,DataGrid 调整行详细信息区域大小时不考虑根元素的边距,可能导致内容被裁剪。可添加额外容器来解决此问题。
可通过设置
DataGrid.RowDetailsVisibilityMode
属性来配置行详细信息区域的显示行为。默认值为
VisibleWhenSelected
,表示仅在选中行时显示;也可设置为
Visible
以显示所有行的详细信息,或设置为
Collapsed
隐藏所有行的详细信息,后续可在代码中更改该属性。
9. 冻结列
冻结列在滚动到右侧时会固定在 DataGrid 的左侧。例如,将“Product”列冻结后,滚动时该列仍保持可见,且水平滚动条仅在可滚动列下方延伸。
列冻结功能对于非常宽的网格很有用,可确保某些信息(如产品名称或唯一标识符)始终可见。要使用此功能,将列的
IsFrozen
属性设置为
True
,示例如下:
<data:DataGridTextColumn Header="Product" Width="175" IsFrozen="True"
Binding="{Binding ModelName}"></data:DataGridTextColumn>
通过以上方法,可充分利用 DataGrid 的各种功能,实现灵活的数据显示和定制。
数据网格控件的使用与定制
10. 综合应用示例
为了更好地展示上述各项功能的综合应用,下面给出一个完整的示例。假设我们有一个产品列表,包含产品名称、价格、描述和是否有库存等信息,我们将使用 DataGrid 来展示这些数据,并应用前面提到的各种定制功能。
<data:DataGrid x:Name="gridProducts" Margin="5" AutoGenerateColumns="False"
CanUserResizeColumns="True" CanUserReorderColumns="True"
RowHeight="70" ColumnWidth="Auto">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Product" Width="175" IsFrozen="True"
Binding="{Binding ModelName}">
</data:DataGridTextColumn>
<data:DataGridTextColumn Header="Price" Binding="{Binding UnitCost, StringFormat='C'}"
Width="Auto">
</data:DataGridTextColumn>
<data:DataGridTextColumn Header="Description" Width="400"
Binding="{Binding Description}">
<data:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</data:DataGridTextColumn.ElementStyle>
</data:DataGridTextColumn>
<data:DataGridCheckBoxColumn Header="In Stock" Binding="{Binding IsInStock}"
Content="Available" IsThreeState="False">
</data:DataGridCheckBoxColumn>
</data:DataGrid.Columns>
<data:DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border>
<Border Margin="10" Padding="10" BorderBrush="SteelBlue" BorderThickness="3"
CornerRadius="5">
<TextBlock Text="{Binding AdditionalInfo}" TextWrapping="Wrap" FontSize="10">
</TextBlock>
</Border>
</Border>
</DataTemplate>
</data:DataGrid.RowDetailsTemplate>
<data:DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<EventSetter Event="LoadingRow" Handler="gridProducts_LoadingRow"></EventSetter>
</Style>
</data:DataGrid.RowStyle>
</data:DataGrid>
' Reuse brush objects for efficiency in large data displays.
Private highlightBrush As New SolidColorBrush(Colors.Orange)
Private normalBrush As New SolidColorBrush(Colors.White)
Private Sub gridProducts_LoadingRow(ByVal sender As Object, _
ByVal e As DataGridRowEventArgs)
' Check the data object for this row.
Dim product As Product = CType(e.Row.DataContext, Product)
' Apply the conditional formatting.
If product.UnitCost > 100 Then
e.Row.Background = highlightBrush
Else
' Restore the default white background. This ensures that used,
' formatted DataGrid object are reset to their original appearance.
e.Row.Background = normalBrush
End If
End Sub
在这个示例中:
- 我们关闭了自动列生成,显式定义了四列,包括产品名称、价格、描述和是否有库存。
- 产品名称列被冻结,确保滚动时始终可见。
- 价格列使用了货币格式。
- 描述列设置了文本换行样式。
- 库存列使用了
DataGridCheckBoxColumn
来显示布尔值。
- 行详细信息区域显示了产品的额外信息。
- 通过
LoadingRow
事件对高价产品的行背景进行了高亮显示。
11. 性能考虑
在使用 DataGrid 时,性能是一个需要关注的重要方面。以下是一些性能优化的建议:
-
减少不必要的自动调整
:自动调整列宽在某些情况下可能会导致性能下降,尤其是在数据量较大时。如果不需要自动调整列宽,可使用固定大小或比例大小的列。
-
避免在
LoadingRow
事件中进行耗时操作
:如前面所述,
LoadingRow
事件在滚动时会频繁触发,因此应避免在其中放置耗时的代码,以免影响滚动性能。
-
合理使用虚拟化
:DataGrid 本身支持虚拟化,可有效降低内存开销。确保在大数据集的情况下充分利用这一特性。
12. 总结
DataGrid 是一个功能强大的数据显示控件,提供了丰富的定制选项,可满足各种不同的需求。通过显式定义列、控制列宽、格式化行和列、添加行详细信息以及冻结列等功能,我们可以创建出高度定制化的数据网格。
同时,在使用过程中需要注意性能问题,合理配置各项属性和事件处理程序,以确保应用程序的流畅运行。希望通过本文的介绍,你能更好地掌握 DataGrid 的使用和定制技巧,在实际项目中发挥其最大的作用。
以下是一个总结 DataGrid 主要定制功能的表格:
| 定制功能 | 实现方法 |
| ---- | ---- |
| 列调整大小和重新排列 | 设置
CanUserResizeColumns
、
CanUserReorderColumns
等属性 |
| 定义列 | 设置
AutoGenerateColumns
为
False
,并填充
DataGrid.Columns
集合 |
| 列格式化和样式设置 | 使用
ElementStyle
、
EditingElementStyle
等属性 |
| 控制列宽 | 设置
Width
属性为固定值、自动值或比例值 |
| 行格式化 | 处理
DataGrid.LoadingRow
事件 |
| 行详细信息 | 设置
DataGrid.RowDetailsTemplate
和
DataGrid.RowDetailsVisibilityMode
属性 |
| 冻结列 | 设置列的
IsFrozen
属性为
True
|
下面是一个简单的 mermaid 流程图,展示了使用 DataGrid 的基本步骤:
graph TD;
A[创建 DataGrid] --> B[关闭自动列生成];
B --> C[定义列];
C --> D[设置列属性和样式];
D --> E[设置行属性和样式];
E --> F[添加行详细信息];
F --> G[应用定制功能(如冻结列)];
G --> H[处理事件(如 `LoadingRow`)];
通过以上步骤和定制功能,你可以创建出满足各种需求的数据网格控件。
超级会员免费看
871

被折叠的 条评论
为什么被折叠?



