XtraGrid 提供了事件动态加载细节数据来实现主/从关系。 本主题提供了关于此功能的信息。 可以使用动态细节数据加载,而无需考虑数据源类型。 或者,可以通过为数据源支持 IRelationList 接口,来实现此目的。 请参阅 主/从关系: 为自定义对象实现主/从关系 主题来获得更多信息。
如果数据源表示 DataTable 对象,则可以使用由数据源提供的方法来实现主/从关系。 但是,在这种情况下,主表数据和细节数据始终存放在内存中。 动态加载细节数据可以提升应用程序的性能。可以同时使用细节数据动态加载事件和数据源的方法来设置主/从关系。 在这种情况下,在事件中允许重写数据源的主/从设置。
主/从模式概述 文档提供了关于实现主/从模式的方法的总说明。
XtraGrid 使用 视图 技术显示数据。 要获得关于在主/从模式中的视图的信息,请参阅 模式视图与克隆视图 主题。
细节数据动态加载事件
- 指定不同数目的主/从关系,因此为主控行指定不同数目的细节视图
- 为属于不同主控行但对应于相同关系的细节数据,使用不同的视图来呈现
- 控制细节数据是否可以在当前显示,等等
-
GridView.MasterRowGetRelationCount 事件。 接管此事件来为每个主控行指定主/从关系的数目。 主控行的 句柄 由事件的 RowHandle 参数标识。 必须通过 RelationCount 参数设置关系数目。 当其他动态细节数据加载事件发生时,它们获取引用当前细节数据的 RelationIndex 参数。 此参数的取值从 0 到 RelationCount - 1 之间变动。
网格控件也激发 MasterRowGetRelationCount 事件,事件的 RowHandle 参数设置为 GridControl.InvalidRowHandle 字段值。 如果 RelationCount 参数被设置为正数,则网格视图将显示 主/从展开按钮。 否则,展开按钮被隐藏。 在这种情况下,通过代码或双击 行指示器面板 的单元格,仍然可以展开细节视图。
-
GridView.MasterRowEmpty 事件。 接管此事件来指定当前细节视图是否有数据。 通过主控行句柄和关系索引来识别细节视图。 如果细节视图不包含数据,则不能打开它。
在某些情况下,可能需要隐藏特定的细节视图。 要达到此目的,可以把事件的 IsEmpty 参数设置为 true,即使是细节视图中包含数据。
但是,如果 GridOptionsDetail.AllowExpandEmptyDetails 属性值设置为 true,则网格控件允许打开空细节视图。 这可以用于允许最终用户把新记录添加到空细节视图中。 - GridView.MasterRowGetChildList 事件。 接管此事件来为当前细节视图提供数据。 由主控行句柄和关系的索引标识细节视图。
-
GridView.MasterRowGetRelationName 事件。 接管此事件为当前关系 (细节) 提供名称。
在几种情况下使用提供的名称。 首先,用于获取与指定关系名称相关联的默认 模式视图,并且模式视图被用作创建实际细节视图 (克隆) 的模板。 所需的模式视图从 GridControl.LevelTree 树获取,在树中特定的模式视图与关系相关联。 通过接管 GridView.MasterRowGetLevelDefaultView 事件,可以改变默认的模式视图选择。
其次,在默认情况下,关系名称用作细节视图的显示名称。 在相应的 细节标签 中和 细节工具提示 中显示该名称。 要定制显示标题,则可以使用模式视图的 BaseView.ViewCaption 属性或主表视图的 GridView.MasterRowGetRelationDisplayCaption 事件。
-
GridView.MasterRowGetRelationDisplayCaption 事件。 接管此事件为特定的关系提供显示标题。
如果 GridView.MasterRowGetRelationName 事件被接管,则通过事件的 RelationName 参数提供的名称作为被处理关系的默认显示标题。 也可以通过呈现关系的模式视图的 BaseView.ViewCaption 属性定制显示标题。
通过 GridView.MasterRowGetRelationDisplayCaption 事件提供的名称有最高的优先级。
- GridView.MasterRowGetLevelDefaultView 事件。 接管此事件来为当前呈现的细节视图显式提供模式视图。 通常,如果所需的模式视图不属于 GridControl.LevelTree 树,则需要接管此事件。 否则,在大多数情况下,可以通过 GridView.MasterRowGetRelationName 事件间接提供模式视图。
示例
网格的绑定数据源是一个 ArrayList,其中包含了三个 Record 对象。 每个 Record 对象都公开了 Name 公共属性,此属性在类的构造函数中初始化。
C# | 复制代码 |
---|---|
private void InitData() { ArrayList records = new ArrayList(); records.Add(new Record("first")); records.Add(new Record("second")); records.Add(new Record("third")); gridControl1.DataSource = records; } |
Visual Basic | 复制代码 |
---|---|
Private Sub InitData() Dim records As New ArrayList records.Add(New Record("first")) records.Add(New Record("second")) records.Add(New Record("third")) gridControl1.DataSource = records End Sub |
一个二维数组被定义,用于标识每个行可用的细节数据。 每个元素都为特定行定义了一个关系名称和细节索引 (在本例中,细节数据的最大数目是 3)。
C# | 复制代码 |
---|---|
private object[,] relations = { {"Products", "Customers", "Shippers"}, { null, null, null}, {"Employees", null, null}}; |
Visual Basic | 复制代码 |
---|---|
Private relations As Object(,) = {{ _ "Products", "Customers", "Shippers"}, { _ Nothing, Nothing, Nothing}, { _ "Employees", Nothing, Nothing}} |
C# | 复制代码 |
---|---|
using DevExpress.XtraGrid.Views.Grid //Specifies the maximum number of details private void gridView1_MasterRowGetRelationCount(object sender, MasterRowGetRelationCountEventArgs e) { e.RelationCount = 3; } //Specifies whether a specific detail contains data //The detail should not be displayed if the corresponding relations element is null private void gridView1_MasterRowEmpty(object sender, MasterRowEmptyEventArgs e) { e.IsEmpty = IsRelationEmpty(e.RowHandle, e.RelationIndex); } bool IsRelationEmpty(int rowHandle, int relationIndex) { return rowHandle == GridControl.InvalidRowHandle || relations[rowHandle, relationIndex] == null; } //Get child data for specific relations //The ChildRecordsProducts, ChildRecordsCustomers, ChildRecordsShippers and Records //are custom classes derived from ArrayList private void gridView1_MasterRowGetChildList(object sender, MasterRowGetChildListEventArgs e) { if(IsRelationEmpty(e.RowHandle, e.RelationIndex)) return; string s = relations[e.RowHandle, e.RelationIndex].ToString(); switch(s) { case "Products": e.ChildList = new ChildRecordsProducts(); break; case "Customers": e.ChildList = new ChildRecordsCustomers(); break; case "Shippers": e.ChildList = new ChildRecordsShippers(); break; case "Employees": e.ChildList = new Records(); break; } } //Provide names for relations //The names are used to determine pattern Views for representing detail data private void gridView1_MasterRowGetRelationName(object sender, MasterRowGetRelationNameEventArgs e) { if(IsRelationEmpty(e.RowHandle, e.RelationIndex)) e.RelationName = ""; else e.RelationName = relations[e.RowHandle, e.RelationIndex].ToString(); } |
Visual Basic | 复制代码 |
---|---|
Imports DevExpress.XtraGrid.Views.Grid 'Specifies the maximum number of details Private Sub gridView1_MasterRowGetRelationCount(ByVal sender As Object, _ ByVal e As .MasterRowGetRelationCountEventArgs) _ Handles gridView1.MasterRowGetRelationCount e.RelationCount = 3 End Sub 'Specifies whether a specific detail contains data 'The detail should not be displayed if the corresponding relations element is null Private Sub gridView1_MasterRowEmpty(ByVal sender As Object, _ ByVal e As MasterRowEmptyEventArgs) _ Handles gridView1.MasterRowEmpty e.IsEmpty = IsRelationEmpty(e.RowHandle, e.RelationIndex) End Sub Function IsRelationEmpty(ByVal rowHandle As Integer, ByVal relationIndex As Integer) As Boolean If (rowHandle = DevExpress.XtraGrid.GridControl.InvalidRowHandle) Then Return True Return relations(rowHandle, relationIndex) Is Nothing End Function 'Get child data for specific relations 'The ChildRecordsProducts, ChildRecordsCustomers, ChildRecordsShippers and Records 'are custom classes derived from ArrayList Private Sub gridView1_MasterRowGetChildList(ByVal sender As Object, _ ByVal e As MasterRowGetChildListEventArgs) _ Handles gridView1.MasterRowGetChildList If IsRelationEmpty(e.RowHandle, e.RelationIndex) Then Return Dim s As String = relations(e.RowHandle, e.RelationIndex).ToString() Select Case s Case "Products" e.ChildList = New ChildRecordsProducts Case "Customers" e.ChildList = New ChildRecordsCustomers Case "Shippers" e.ChildList = New ChildRecordsShippers Case "Employees" e.ChildList = New Records End Select End Sub 'Provide names for relations 'The names are used to determine pattern Views for representing detail data Private Sub gridView1_MasterRowGetRelationName(ByVal sender As Object, _ ByVal e As MasterRowGetRelationNameEventArgs) _ Handles gridView1.MasterRowGetRelationName If IsRelationEmpty(e.RowHandle, e.RelationIndex) Then e.RelationName = "" Else e.RelationName = relations(e.RowHandle, e.RelationIndex).ToString() End If End Sub |
Products、Customers、Shippers 和 Employees 关系的子数据分别通过自定义的 ChildRecordsProducts、ChildRecordsCustomers、ChildRecordsShippers 和 Records 类来表示。 请参阅指南项目中这些类的实现。
基于由 GridView.MasterRowGetRelationName 事件处理程序取回的关系名称,呈现关系的视图被隐式确定。 这此指南中,在设计时刻使用 层设计器(Level Designer) 创建模式视图,并与关系名称相关联:
注意,在 层设计器(Level Designer) 中为 Employees、Products 和 Customers 关系定义了模式视图。 Shippers 关系没有模式视图 。 而是基于主表视图 (gridView1) 的设置来创建它的细节视图。
例如,要获得关于通过代码把视图指派到关系的信息,请参阅 主/从关系: 使用 DataTable 章节中的示例。 下面的插图展示了为第一个主控行呈现 Products 关系的一个细节卡片视图:通过网格视图呈现 Shippers 关系: