本主题提供了关于在网格视图的分组模式中如何组织行的信息。 在迭代和操作分组行时,应该考虑这一点。 要获得关于分组的信息,请参阅 分组概述 文档。
分组行
当应用分组时,分组行把数据组织为树。 分组行是虚对象。 在绑定数据源中不存在分组行,而只是存储数据行。 仅在分组模式中分组行才被创建,目的是把相同取值的记录组合到分组列中。 如果按照单个列进行分组,则网格视图为唯一的列值创建分组行,然后把数据记录放置在适当的组中。 如果按照多列分组,则创建嵌套的数据组。 数据行被显示在层级的最底部,并且可以通过递归展开分组行来访问它们。
每个数据行和分组行 (可视的或隐藏的) 都通过一个称为行句柄的唯一整数值进行标识。 数据行的句柄是非负数。 顶部的分组行的句柄是 -1。 下面的分组行的句柄是 -2, 等等。 根据排序、分组和筛选设置,行句柄确定了行在视图内出现的顺序。 下面的插图展示了一个示例网格视图的行句柄:
要获得更多关于行句柄,以及如何使用行句柄来引用特定行的信息。 请参阅 行与卡片识别 章节。
要查明行句柄是否引用了一个分组行或数据行,则使用 GridView.IsGroupRow 方法。
按照上述说明,在分组模式中,所有行形成一个层次结构。 可以通过使用 GridView.GetRowLevel 方法来获取每行的分组层级,也即它在分组层次结构中的位置。 对于显示在顶层级中的行,此方法返回 0。 对于根行的直属子行,此方法返回 1,等等。 最大的分组层级索引与分组列的数目相匹配。 例如,对于上述插图中的所有数据行, GridView.GetRowLevel 将返回 2。 也可以通过可视索引返回特定行的分组层级。 要达到此目的,则使用 GridView.GetVisibleRowLevel 方法。 要获得更多关于可视索引的信息,请参阅 行与卡片识别 文档。
要迭代属于特定分组行的子行,则可以使用下列方法:- GridView.GetChildRowCount 返回分组行的直属子行的数目。 例如,对于分组行“Trademark:Mercedes-Benz” (行句柄为 -3),此方法返回 2,因为该行有两个直属子行 (句柄为 -4 和 -5 的分组行)。
- GridView.GetChildRowHandle 返回特定子行的句柄。 通过子行在其他子行之间的索引来引用子行,并且子行的索引可以在 0 至 GridView.GetChildRowCount 减去 1 区间变化。 例如,对于上述插图中的分组行“Trademark:Mercedes-Benz”,它的子行的索引可以在 0 至 1 间变化。
- GridView.GetParentRowHandle 获取直属父行的句柄。 例如,对于“Cyl: 4”分组行 (行句柄是 -5),此方法返回 -3。 这引用了“Trademark:Mercedes-Benz”分组行。
- GridView.GetDataRowHandleByGroupRowHandle 允许获取属于某个组中的第一个数据行的句柄。 即使目标数据行没有直属子行,也可以使用此方法。
操作组中的行
始终牢记在应用了分组、排序、或筛选时,改变行的取值可能导致行被重设顺序。 当改变多个行的取值时,不应使用行句柄来引用特定的行,这是因为行句柄反映行的顺序。 而是使用行对象来引用它们。 可以通过 ColumnView.GetRow 和 ColumnView.GetDataRow 方法来获取特定行句柄对应的行对象。 这些方法需要一个行句柄作为参数,并返回表示数据源中相应行的对象。 可以使用 ColumnView.GetRow,而不管数据源的类型如何。 ColumnView.GetDataRow 仅当绑定数据源表示一个 DataView 对象时有效。 在这种情况下,此方法返回相应的 DataRow。 对于其他数据源,此方法返回 null (在 Visual Basic 中为 Nothing)。
在修改多个行之前,应该把相关联的对象存储到一个列表中。 然后使用由数据源提供的方法来修改这些行的数据。下面的示例展示了如何为属于获得焦点的数据组的所有数据行修改“Price”列的取值。 在 buttonDiscount_Click 事件处理程序中,创建了一个数组列表 (rowsToDiscount) 来存储需要被修改的行。 接下来,如果获得焦点的行是一个分组行,则使用 getChildRows 方法把它的子数据行添加到列表中。 如果数据行获得焦点,则仅有该行被添加到列表中。
getChildRows 方法搜索属于特定数据组的数据行,并且把它们添加到一个数组列表中。 它使用 GridView.GetChildRowCount 和 GridView.GetChildRowHandle 方法来遍历此数据组。 getChildRows 方法把行对象而不是行句柄添加到列表中。 也要注意如果行已经在列表中,则不再添加它。
被检查的视图需要绑定到一个 DataView 数据源。 对于这种数据源类型,在本示例中使用的 ColumnView.GetRow 方法返回相应的 DataRowView 对象。 在 discount 方法中,列表项的类型首先被转换为 DataRowView。 然后获取 DataRow 对象 (通过 DataRowView.Row 属性获取),并且用于修改该行。
C# | 复制代码 |
---|---|
using DevExpress.XtraGrid.Views.Grid; //... private void buttonDiscount_Click(object sender, System.EventArgs e) { GridView view = gridView1; int rowHandle = view.FocusedRowHandle; ArrayList rowsToDiscount = new ArrayList(); //Get related data rows if(view.IsGroupRow(rowHandle)) getChildRows(view, rowHandle, rowsToDiscount); else rowsToDiscount.Add(view.GetRow(rowHandle)); //Change the values of the rows view.BeginUpdate(); discount(rowsToDiscount); view.EndUpdate(); } //Returns the child data rows for the given group row public void getChildRows(GridView view, int groupRowHandle, ArrayList childRows) { if(!view.IsGroupRow(groupRowHandle)) return; //Get the number of immediate children int childCount = view.GetChildRowCount(groupRowHandle); for(int i=0; i<childCount; i++){ //Get the handle of a child row with the required index int childHandle = view.GetChildRowHandle(groupRowHandle, i); //If the child is a group row, then add its children to the list if(view.IsGroupRow(childHandle)) getChildRows(view, childHandle, childRows); else { // The child is a data row. // Add it to the childRows as long as the row wasn't added before object row = view.GetRow(childHandle); if(!childRows.Contains(row)) childRows.Add(row); } } } //Changes the values of the Price column for the specified rows public void discount(ArrayList rows) { for(int i = 0; i < rows.Count; i++) { DataRow row = (rows[i] as DataRowView).Row; decimal oldValue = (decimal)row["Price"]; row["Price"] = oldValue * 0.95m; } } |
Visual Basic | 复制代码 |
---|---|
Imports DevExpress.XtraGrid.Views.Grid '... Private Sub ButtonDiscount_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles ButtonDiscount.Click Dim View As GridView = GridView1 Dim rowHandle As Integer = View.FocusedRowHandle Dim rowsToDiscount As ArrayList = New ArrayList 'Get related data rows If View.IsGroupRow(rowHandle) Then getChildRows(View, rowHandle, rowsToDiscount) Else rowsToDiscount.Add(View.GetRow(rowHandle)) End If 'Change the values of the rows View.BeginUpdate() discount(rowsToDiscount) View.EndUpdate() End Sub 'Returns the child data rows for the given group row Public Sub getChildRows(ByVal View As GridView, ByVal groupRowHandle As Integer, _ ByVal childRows As ArrayList) If Not View.IsGroupRow(groupRowHandle) Then Return 'Get the number of immediate children Dim childCount As Integer = View.GetChildRowCount(groupRowHandle) Dim i As Integer For i = 0 To childCount - 1 'Get the handle of a child row with the required index Dim childHandle As Integer = View.GetChildRowHandle(groupRowHandle, i) 'If the child is a group row, then add its children to the list If View.IsGroupRow(childHandle) Then getChildRows(View, childHandle, childRows) Else ' The child is a data row. ' Add it to the childRows as long as the row was not added before Dim row As Object = View.GetRow(childHandle) If Not childRows.Contains(row) Then childRows.Add(row) End If Next End Sub 'Changes the values of the Price column for the specified rows Public Sub discount(ByVal rows As ArrayList) Dim i As Integer For i = 0 To rows.Count - 1 Dim row As DataRow = CType(rows(i), DataRowView).Row Dim oldValue As Decimal = row("Price") row("Price") = oldValue * 0.95 Next End Sub |
添加和删除记录 主题举例说明了如何把行添加到特定的数据组中。
要删除特定的分组行,则可以使用 ColumnView.DeleteRow 方法。
展开和折叠分组行
要获取分组行的展开状态,则使用 GridView.GetRowExpanded 方法。 此方法返回 true 或 false,这取决于被检查的分组行是否被展开或折叠。 GridView.ExpandGroupRow、GridView.CollapseGroupRow 和 GridView.SetRowExpanded 方法可以用于展开和折叠分组行。 这些方法也有递归展开/折叠分组行的重载 (在这种情况下,嵌套的分组行将被展开/折叠)。
下面的示例演示了如何为获得焦点的分组行切换展开状态:C# | 复制代码 |
---|---|
using DevExpress.XtraGrid.Views.Grid; //... GridView View = gridView1; bool expanded = View.GetRowExpanded(view.FocusedRowHandle); view.SetRowExpanded(view.FocusedRowHandle, !expanded); |
Visual Basic | 复制代码 |
---|---|
Imports DevExpress.XtraGrid.Views.Grid '... Dim View As GridView = GridView1 Dim expanded As Boolean = View.GetRowExpanded(view.FocusedRowHandle) view.SetRowExpanded(view.FocusedRowHandle, Not expanded) |
下一个示例展示了如何显示“Is In Stock”列的取值被设置为 false 的行。
C# | 复制代码 |
---|---|
using DevExpress.XtraGrid.Views.Grid; //... GridView View = gridView1; int rowHandle = -1; do { rowHandle = View.LocateByValue(rowHandle+1, View.Columns["Is In Stock"], false); View.MakeRowVisible(rowHandle, false); } while(rowHandle != GridControl.InvalidRowHandle); |
Visual Basic | 复制代码 |
---|---|
Imports DevExpress.XtraGrid.Views.Grid '... Dim View As GridView = GridView1 Dim rowHandle As Integer = -1 Do rowHandle = View.LocateByValue(rowHandle + 1, View.Columns("Is In Stock"), False) View.MakeRowVisible(rowHandle, False) Loop Until rowHandle = GridControl.InvalidRowHandle |
通过使用 GridView.ExpandAllGroups 和 GridView.CollapseAllGroups 方法,可以立即展开或折叠所有组。 这些方法分别改变行的展开状态。
在展开分组行之前,网格视图产生 GridView.GroupRowExpanding 事件,此事件可以防止行被展开。 在行已经被展开之后, GridView.GroupRowExpanded 事件发生。
网格视图提供了 GridView.GroupRowCollapsing 和 GridView.GroupRowCollapsed 事件,它们在行被折叠之前和之后发生。 GridView.GroupRowCollapsing 事件可以用于防止特定的列被折叠。
下面是一些关于 GridView.GroupRowExpanding、GridView.GroupRowExpanded、 GridView.GroupRowCollapsing 和 GridView.GroupRowCollapsed 事件功能的细节:
- 当所有分组行都被一次性展开/折叠时 (通过代码或上下文菜单),则相应的事件仅发生一次 (不为每个被展开的分组行重复发生)。 在这种情况下,事件的 RowHandle 参数设置为 GridControl.InvalidRowHandle 值。
- 当分组行被递归展开/折叠时 (嵌套的行也被展开/折叠),相应的事件只发生一次 (为该行)。 事件的参数引用了该行。 对于嵌套的行,事件不发生。
- 当由于调用 GridView.MakeRowVisible 方法或把行句柄指派到 ColumnView.FocusedRowHandle 属性而导致分组行被展开时,事件不发生。