数据控件 DataGrid 全解析
1. 冻结列规则
冻结列必须位于网格的左侧。若冻结一列,该列必须是最左侧的列;若冻结两列,则必须是左侧的前两列,以此类推。
2. 选择功能
-
单项选择
:和普通列表控件一样,DataGrid 允许用户选择单个项目。当选择发生变化时,可对
SelectionChanged事件做出响应。要确定当前选择的数据对象,可使用SelectedItem属性。 -
多项选择
:若要让用户能够选择多行,需将
SelectionMode属性设置为Extended(默认值为Single)。用户选择多行时,需按住Shift或Ctrl键。可通过SelectedItems属性检索所选项目的集合。 -
编程式选择
:可以使用
SelectedItem属性以编程方式设置选择。若设置的选择项当前不在视图中,可调用DataGrid.ScrollIntoView()方法,使 DataGrid 滚动,直至所选项目可见。
3. 排序功能
-
内置排序
:只要绑定的集合实现了
IList(如List(Of T)和ObservableCollection(Of T)集合),DataGrid 就具备内置排序功能。用户点击列标题即可使用排序,首次点击按数据类型升序排序(如数字从 0 开始排序,字母按字母顺序排序),再次点击则反转排序顺序。列标题最右侧会出现箭头,升序时箭头向上,降序时箭头向下,多次点击列标题时,箭头会有快速动画翻转效果。用户按住Shift键点击可按多列排序。 -
排序控制选项
:
-
SortMemberPath 属性
:每列都有
SortMemberPath属性,可指定用于排序的绑定数据对象的属性。若未设置该属性,则使用绑定数据进行排序。对于DataGridTemplateColumn,必须使用SortMemberPath,否则该列不支持排序。 -
PagedCollectionView 类
:
PagedCollectionView包装普通集合,提供排序、过滤、分组和分页功能。 -
自定义模板
:若不喜欢默认的排序箭头或想添加更炫酷的动画,可使用
DataGrid.ColumnHeaderStyle属性应用新模板。该模板有三种关键状态:未排序状态、升序排序状态和降序排序状态,可自定义这些状态的视觉效果。
-
SortMemberPath 属性
:每列都有
-
禁用排序
:可将
CanUserSortColumns属性设置为False禁用所有列的排序,或通过设置列的CanUserSort属性禁用特定列的排序。
4. 编辑功能
-
编辑限制
:
-
DataGrid.IsReadOnly
:当该属性为
True时,用户无法编辑任何内容。 -
DataGridColumn.IsReadOnly
:当该属性为
True时,用户无法编辑该列的任何值。 -
只读属性
:若数据对象的属性没有属性设置器,DataGrid 会自动禁用该列的编辑,就像设置了
DataGridColumn.IsReadOnly为True一样。若属性不是简单的文本、数字或日期类型,DataGrid 会将其设为只读,但可通过使用DataGridTemplateColumn解决。
-
DataGrid.IsReadOnly
:当该属性为
-
编辑模式表现
:不同列类型在编辑模式下表现不同。
DataGridTextColumn显示一个无缝的文本框,DataGridCheckBoxColumn显示一个复选框,DataGridTemplateColumn则允许使用更专业的输入控件(如DatePicker或ComboBox)替换标准编辑文本框。 -
模板编辑
:
DataGridTemplateColumn支持两个模板,CellTemplate决定单元格非编辑状态的外观,CellEditingTemplate指定编辑模式下显示的控件,使用双向绑定表达式连接到相应字段。以下是一个日期列的示例:
<data:DataGridTemplateColumn Header="Date Added">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding DateAdded, Converter={StaticResource DateOnlyConverter}}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<controls:DatePicker SelectedDate="{Binding DateAdded, Mode=TwoWay}"></controls:DatePicker>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
还可以使用模板列提供数据输入的查找列表,例如限制
Category
选择为预定义类别列表:
<data:DataGridTemplateColumn Header="Category">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding CategoryName}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Margin="4" ItemsSource="{Binding CategoryChoices}" SelectedItem="{Binding CategoryName, Mode=TwoWay}"></ComboBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
5. 验证和编辑事件
-
基本验证
:DataGrid 自动支持基本验证系统,当数据绑定系统出现问题(如无法将输入文本转换为适当的数据类型)或属性设置器抛出异常时,错误消息会以红色弹出框形式显示在违规列旁边。
DataGridTextColumn自动使用支持验证的绑定表达式,对于DataGridTemplateColumn,需在CellEditingTemplate的绑定表达式中添加ValidatesOnExceptions和NotifyOnValidationError属性。
<data:DataGridTemplateColumn Header="Price">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding UnitCost, StringFormat='C'}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Margin="4" Text="{Binding UnitCost, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"></TextBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
-
编辑事件
:DataGrid 有多个编辑事件,如下表所示:
| 事件名称 | 描述 |
| — | — |
| BeginningEdit | 单元格即将进入编辑模式时触发,可检查当前编辑的列和行、单元格值,并使用DataGridBeginningEditEventArgs.Cancel属性取消操作。 |
| PreparingCellForEdit | 用于模板列,可在此对编辑控件进行最后的初始化操作,使用DataGridPreparingCellForEditEventArgs.EditingElement访问CellEditingTemplate中的元素。 |
| CellEditEnding | 单元格即将退出编辑模式时触发,DataGridCellEditEndingEventArgs.EditAction可告知用户是尝试接受编辑(如按 Enter 键或点击其他单元格)还是取消编辑(按 Escape 键),可检查新数据并设置Cancel属性回滚更改。 |
| CellEditEnded | 单元格恢复正常后触发,可用于更新其他控件或显示更改提示消息。 |
| RowEditEnding | 提供当前所有 HTTP cookie 的集合,可读写这些 cookie 的值。 |
| RowEditEnded | 用户离开编辑行后触发,可用于更新其他控件或显示更改提示消息。 |
若需要执行特定于页面的验证逻辑,可编写自定义验证逻辑响应
CellEditEnding
和
RowEditEnding
事件。DataGrid 支持数据注解的方式与普通输入控件不同,若属性设置器使用
Validator.ValidateProperty()
方法检查无效值并抛出
ValidationException
,DataGrid 会立即识别错误并显示红色弹出框错误消息;若不使用验证器,DataGrid 仍会验证所有属性和整个对象,但直到用户尝试移动到另一行时才进行验证,若检测到验证错误,会将用户返回到无效行并保持编辑模式,错误消息显示在 DataGrid 底部的阴影栏中。
6. PagedCollectionView 的使用
-
基本介绍
:
PagedCollectionView位于System.Windows.Data命名空间,它包装集合,为数据提供排序、过滤、分组和分页功能,可看作是数据的一个窗口,在数据显示在绑定控件(如 DataGrid)之前应用这些操作。 -
使用步骤
:
-
在代码中显式创建
PagedCollectionView,将包含数据的源集合作为构造函数参数。 -
将
PagedCollectionView绑定到相应控件,而不是原始集合。例如,将原来的gridProducts.ItemsSource = e.Result改为:
-
在代码中显式创建
Dim view As New PagedCollectionView(e.Result)
gridProducts.ItemsSource = view
-
排序
:可通过向
PagedCollectionView.SortDescriptions集合添加SortDescription对象应用多级排序。例如,按类别和价格排序的代码如下:
Dim view As New PagedCollectionView(e.Result)
' Sort by category and price.
view.SortDescriptions.Add(New SortDescription("CategoryName", ListSortDirection.Ascending))
view.SortDescriptions.Add(New SortDescription("UnitCost", ListSortDirection.Ascending))
gridProducts.ItemsSource = view
这种方法与 DataGrid 的内置排序完美集成,若用户点击列标题,旧的排序顺序将被放弃,行将重新排序。
-
过滤
:使用
PagedCollectionView.Filter属性设置过滤回调,该回调例程测试每行是否应显示或隐藏,返回True显示行,返回False隐藏行。例如,只显示旅游类产品的代码如下:
Dim view As New PagedCollectionView(e.Result)
view.Filter = AddressOf SelectTravelProducts
gridProducts.ItemsSource = view
Private Function SelectTravelProducts(ByVal filterObject As Object) As Object
Dim product As Product = CType(filterObject, Product)
Return (product.CategoryName = "Travel")
End Function
-
分组
:DataGrid 支持分组,可将行组织成逻辑类别。基本思路是选择用于分组的属性(如
CategoryName),具有相同属性值的对象(如相同类别的产品)会被放入一个组中,可在 DataGrid 显示中展开或折叠组。实现分组的步骤如下:- 选择分组字段。
-
向
PagedCollectionView.GroupDescriptions集合添加PropertyGroupDescription对象。例如,按类别分组的代码如下:
Dim view As New PagedCollectionView(e.Result)
view.GroupDescriptions.Add(New PropertyGroupDescription("CategoryName"))
gridProducts.ItemsSource = view
若要进行分组和子分组,可添加多个
PropertyGroupDescription
对象。例如,按类别和产品状态分组的代码如下:
Dim view As New PagedCollectionView(e.Result)
view.GroupDescriptions.Add(New PropertyGroupDescription("CategoryName"))
view.GroupDescriptions.Add(New PropertyGroupDescription("Status"))
gridProducts.ItemsSource = view
DataGrid 允许用户展开和折叠每个组,也可通过
ExpandRowGroup()
和
CollapseRowGroup()
方法以编程方式操作。方法需要两个参数:要操作的组和一个布尔值,表示是否要展开或折叠所有子组。例如,折叠旅游组的代码如下:
For Each group As CollectionViewGroup In view.Groups
If group.Name = "Travel" Then
gridProducts.CollapseRowGroup(group, True)
End If
Next
需要注意的是,理论上
PagedCollectionView
可支持任何绑定的
ItemsControl
,但分组功能目前仅 DataGrid 支持。标准的
PagedCollectionView
分组是精确匹配值,若要创建更广泛的组,可使用
PropertyGroupDescription.Converter
属性。另外,可使用
DataGrid.RowGroupHeaderStyles
属性更改每个组前面的标题外观。例如,更改背景和前景颜色的代码如下:
<data:DataGrid.RowGroupHeaderStyles>
<Style TargetType="data:DataGridRowGroupHeader">
<Setter Property="Background" Value="#FF112255" />
<Setter Property="Foreground" Value="#FFEEEEEE" />
</Style>
</data:DataGrid.RowGroupHeaderStyles>
数据控件 DataGrid 全解析
7. 功能总结与注意事项
-
功能总结
- 选择功能 :支持单项和多项选择,可通过属性设置和事件响应实现灵活的选择操作。
-
排序功能
:内置排序方便用户操作,同时提供多种方式进行排序控制,包括属性设置、使用
PagedCollectionView类和自定义模板。 - 编辑功能 :支持编辑,可对编辑权限进行多方面限制,不同列类型在编辑模式有不同表现,模板编辑提供了更灵活的输入控件选择。
- 验证功能 :自动支持基本验证系统,通过编辑事件可实现自定义验证逻辑,对数据注解的支持方式与普通输入控件不同。
-
分组与分页
:借助
PagedCollectionView可实现排序、过滤、分组和分页功能,分组功能目前仅 DataGrid 支持。
-
注意事项
- 冻结列必须在网格左侧,遵循特定规则。
-
使用
DataGridTemplateColumn时,排序和验证需要额外设置相关属性。 - 不使用验证器时,DataGrid 的验证时机和错误显示方式与使用验证器不同,可能导致用户体验差异。
-
对于分组功能,虽然理论上
PagedCollectionView可支持其他ItemsControl,但目前只有 DataGrid 能显示组标题。
8. 流程图示例
下面是一个简单的 DataGrid 编辑操作流程图:
graph TD
A[开始] --> B[用户双击单元格]
B --> C{是否允许编辑?}
C -- 是 --> D[进入编辑模式]
C -- 否 --> E[保持非编辑状态]
D --> F{编辑完成?}
F -- 是 --> G{验证是否通过?}
F -- 否 --> D
G -- 是 --> H[保存更改]
G -- 否 --> I[提示错误并返回编辑模式]
H --> J[退出编辑模式]
E --> K[结束]
J --> K
I --> D
9. 应用场景分析
- 数据展示与管理 :适用于需要展示大量数据并允许用户进行选择、排序、编辑等操作的场景,如企业资源管理系统中的员工信息表、产品库存表等。
-
数据筛选与分析
:通过
PagedCollectionView的过滤功能,可快速筛选出符合特定条件的数据,便于进行数据分析,如销售数据的筛选和统计。 - 数据分组与整理 :分组功能可将数据按照特定属性进行分类展示,使数据结构更清晰,如电商平台中的商品分类展示。
10. 代码示例总结
以下是本文中涉及的主要代码示例总结:
-
模板编辑日期列
<data:DataGridTemplateColumn Header="Date Added">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding DateAdded, Converter={StaticResource DateOnlyConverter}}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<controls:DatePicker SelectedDate="{Binding DateAdded, Mode=TwoWay}"></controls:DatePicker>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
- 模板编辑类别列
<data:DataGridTemplateColumn Header="Category">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding CategoryName}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Margin="4" ItemsSource="{Binding CategoryChoices}" SelectedItem="{Binding CategoryName, Mode=TwoWay}"></ComboBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
- 验证模板列
<data:DataGridTemplateColumn Header="Price">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="4" Text="{Binding UnitCost, StringFormat='C'}"></TextBlock>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Margin="4" Text="{Binding UnitCost, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"></TextBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
- PagedCollectionView 排序
Dim view As New PagedCollectionView(e.Result)
' Sort by category and price.
view.SortDescriptions.Add(New SortDescription("CategoryName", ListSortDirection.Ascending))
view.SortDescriptions.Add(New SortDescription("UnitCost", ListSortDirection.Ascending))
gridProducts.ItemsSource = view
- PagedCollectionView 过滤
Dim view As New PagedCollectionView(e.Result)
view.Filter = AddressOf SelectTravelProducts
gridProducts.ItemsSource = view
Private Function SelectTravelProducts(ByVal filterObject As Object) As Object
Dim product As Product = CType(filterObject, Product)
Return (product.CategoryName = "Travel")
End Function
- PagedCollectionView 分组
Dim view As New PagedCollectionView(e.Result)
view.GroupDescriptions.Add(New PropertyGroupDescription("CategoryName"))
gridProducts.ItemsSource = view
- 更改组标题样式
<data:DataGrid.RowGroupHeaderStyles>
<Style TargetType="data:DataGridRowGroupHeader">
<Setter Property="Background" Value="#FF112255" />
<Setter Property="Foreground" Value="#FFEEEEEE" />
</Style>
</data:DataGrid.RowGroupHeaderStyles>
11. 总结
DataGrid 是一个功能强大的数据控件,提供了丰富的选择、排序、编辑、验证和分组等功能。通过合理使用其属性、事件和相关类(如
PagedCollectionView
),可以满足各种复杂的数据处理需求。在实际应用中,需要根据具体场景选择合适的功能和设置,同时注意一些特殊情况和注意事项,以确保数据的正确展示和处理。希望本文能帮助你更好地理解和使用 DataGrid 控件。
超级会员免费看
605

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



