我正在使用ComponentOne的DataTree Grid。目前,DataTree网格有2个级别(Parent& Child)。每个网格中的每一行都有一个复选框列,用户可以在其中选择'排。当用户选择Parent Row时会触发事件flexgrid_CellChecked。选择子网格后,触发的事件是flexgrid_ChildCellChecked。我想在DataTree中添加第3级,并在选择最内层网格中的Checkbox时触发相应的事件。我们称之为flexgrid_ChildChildCellChecked。
此事件在DataTree类的Expand(int row)方法中实例化。问题是当扩展第一个子级(级别2)时,可以将事件ChildCellChecked和ChildChildCellChecked添加为处理程序。当扩展第二个子级(级别3)时,这两个事件都为空。
这是带有Expand方法的DataTree类:
public class C1FlexDataTree : C1FlexGrid, ISupportInitialize
{
//--------------------------------------------------------------------------------
#region ** fields
// reference to hidden column that contains details rows for each master record
//
// this is created automatically by a DataSet based on its Relations.
//
// e.g. if the parent table is 'Orders', this could be an 'OrderDetails' table
// with the order details for each order on the master data table.
//
private Column _colChild = null;
// child grid that displays the headers rows over the native header rows.
//
// this grid appears on top of all child controls and prevents children from
// hiding the parent grid's header rows when they scroll.
//
private GridHeader _hdr = null; // <<1.1>>
// fire event to allow setting up child grids
// the event sender is the child grid that was just bound
public event EventHandler SetupColumns;
public event RowColEventHandler ChildCellChecked;
public event RowColEventHandler ChildChildCellChecked;
protected virtual void OnSetupColumns(object sender)
{
if (SetupColumns != null)
SetupColumns(sender, EventArgs.Empty);
}
protected virtual void OnChildCellChecked(object sender, RowColEventArgs e)
{
if (ChildCellChecked != null)
{
ChildCellChecked(sender, e);
}
}
protected virtual void OnChildChildCellChecked(object sender, RowColEventArgs e)
{
if (ChildChildCellChecked != null)
{
ChildChildCellChecked(sender, e);
}
}
// get top-level grid (overall parent)
public C1FlexDataTree ParentGrid
{
get
{
C1FlexDataTree parent = this;
while (parent.Parent is C1FlexDataTree)
parent = parent.Parent as C1FlexDataTree;
return parent;
}
}
// expand row
public bool ExpandRow(int row)
{
// sanity
if (row < Rows.Fixed || row >= Rows.Count)
{
return false;
}
// check that the row is not already expanded
C1FlexDataTree childGrid = Rows[row].UserData as C1FlexDataTree;
if (childGrid != null)
{
return false;
}
// check that we have a data source for this row
object dataSource = _colChild != null? _colChild[row] : null;
if (!(dataSource is IBindingList))
{
return false;
}
// ** fire before collapse event
var e = new RowColEventArgs(row, -1);
OnBeforeCollapse(e);
if (e.Cancel)
{
return false;
}
// add node row (unbound) to display child
Rows.InsertNode(row + 1, -1);
// make new row non-editable (it's just a placeholder)
Rows[row + 1].AllowEditing = false;
// create child grid
childGrid = new C1FlexDataTree();
childGrid.Visible = false;
childGrid.ScrollBars = ScrollBars.Horizontal;
// hook up event handlers
//When there is only 2 levels this 'if' statement is not needed.
//But with 3 levels, the ChildCellChecked is null
if (ChildCellChecked != null)
{
childGrid.CellChecked += new RowColEventHandler(ChildCellChecked);
}
// attach child grid to parent, set data source
Controls.Add(childGrid);
childGrid.DataSource = dataSource;
// save references:
// child grid Tag property contains a reference to the parent row
// parent row UserData contains a reference to the child grid
childGrid.Tag = Rows[row];
Rows[row].UserData = childGrid;
// make child grid visible, move it into position
childGrid.Visible = true;
childGrid.UpdatePosition();
childGrid.Focus();
//When _colChild is null, the 3rd level is being expanded.
//ChildChildCellChecked is null
if (childGrid._colChild == null)
{
childGrid.CellChecked += new RowColEventHandler(ChildChildCellChecked);
}
OnAfterCollapse(e);
// done
return true;
}
我想创建事件,ChildCellChecked用于第二级网格,ChildChildCellChecked用于第3级网格。
网格正确显示,可以展开和折叠。但是,当我单击第3级网格中的复选框时,不会触发任何事件。
如何将事件处理程序与每个级别的网格相关联?
更新
使用您的一个代码段来识别正在扩展的级别,当级别为2时,事件ChildChildCellChecked为空。
在第一级调用期间和第二级调用期间调用方法Expand()时,我附加了一个文档以显示调试模式下的屏幕截图。
在Expand()的第一级调用期间,创建了ChildCellChecked 在Expand()的第二级调用期间,ChildChildCellChecked为null。这导致例外。
在第二级调用Expand()期间,我无法弄清楚为什么委托,ChildChildCellChecked为null。
附加的屏幕截图可以更好地显示错误...... 在调试模式下拍摄2个屏幕截图。
第一个网格已扩展。 这是父网格扩展到第一个子网格的时候。 您可以看到定义了两个BOTH事件。仅创建了ChildCellCheck。
第二个网格已扩展。 当第一个子网格展开以显示第二级网格时,这是错误:
实际上,在第一次调用Expand()期间,两个代理都与各自的事件方法相关联。在第二次调用Expand()期间,两个委托都为空。
我原本以为在创建子网格时,无论级别如何,都会为该子网格创建一个事件处理程序。我不需要第二级网格的第二个事件处理程序。单击复选框时,将触发事件,并且在事件方法中,您可以确定触发事件的子网格级别。
格洛丽亚
答案 0 :(得分:0)
正如我在您的原始帖子here上发布的那样: -
请参阅以下评论:
展开节点时,会将子网格添加到父级的Controls集合中。同样,当您折叠一行时,子网格将从父级的Controls集合中删除。删除子网格时,将清除子项的HeaderGrid的UserData。因此,它将完全使事件处理程序无效。这就是为什么这个代码段无法直接使用的原因。
如果在为每个网格添加事件之前展开所有行,则在每行只有一个子项的情况下,它将完美地工作。但是,这不适用于更一般的情况,因为当只有一个孩子的事件被提出时,所有孩子都会被召唤为孩子。
正如您尝试实现的那样,最好的情况肯定是在DataTree类的ExpandRow方法中添加子事件。这样,无论何时展开行或创建网格,事件处理程序都将附加到网格。可以执行检查以查看当前网格是否应该与“孩子”或“孩子的孩子”事件相关联。请参阅以下代码段:
int level = 0;
C1FlexDataTree parent = new C1FlexDataTree();
parent = childGrid;
while (parent.Parent is C1FlexDataTree)
{
parent = parent.Parent as C1FlexDataTree;
level++;
}
if (level == 1)
{
childGrid.CellChecked += new RowColEventHandler(child_CellChecked);
}
else if (level == 2)
{
childGrid.CellChecked += new RowColEventHandler(childchild_CellChecked);
}
在您的代码段中,您正在检查childGrid.Rows [row]的UserData是否为空。但是,childGrid行的UserData始终为null。每当将子网格添加到网格时,子网格的每一行都会折叠或不可展开。
提示:如果某行的UserData为null,则表示该行已折叠或该行没有任何childGrid
在第三点,我们为“孩子”和“孩子的孩子”创建了活动。这不会为父网格创建事件。因此,您可能必须在DataTree类的构造函数中添加一个片段
if (this.ParentGrid == this)
{
this.CellChecked+=new RowColEventHandler(Parent_CellChecked);
}
<强> 重要 强>:
父网格中的所有子网格都是DataTree。这就是为什么扩展每个子网格的一行也会触发ExpandRow方法并最终尝试添加事件处理程序。请采取正确的措施以确保ChildGrid的ExpandRow方法不会添加父网格之类的事件。这可以通过检查childGrid的级别来确保。它在步骤3中执行。
答案 1 :(得分:0)
请注意,每次创建 DataTree 时,所有嵌入的网格(父对象的子网)都会实现相同的事件。因此,在同一 DataTree 类中创建 ParentCheck , ChildCheck 和 ChildChildCheck 事件是不对的。这就是我们在 DataTree 类中创建 ParentCheck , ChildCheck 和 ChildChildCheck 事件的原因,即使是子项执行< strong> ChilChildCheck 活动。
在 DataTree 类中创建 CellChecked 事件时,会发现所有网格都会继承 CellChecked 事件。这是一个非常有利的情况,我们所要做的就是确定网格的层次级别。
复选框的实现是放置事件中最不可靠的部分。由于复选框只是布尔列而不是字形或嵌入 控件(因为它在某些在线示例中实现),因此复选框不需要与事件单独链接,因此可以通过覆盖基本 CellChecked 事件来实现 CellChecked 事件。
请参阅以下代码段:
protected override void OnCellChecked(RowColEventArgs e)
{
base.OnCellChecked(e);
// Access childs from a flex data tree
if (this.Rows[e.Row].UserData != null)
{
C1FlexDataTree child = this.Rows[e.Row].UserData as C1FlexDataTree;
foreach (Row childRow in child.Rows)
{
if (childRow.Index > 0)
{
childRow[1] = this.Rows[e.Row][1];
if (childRow.UserData != null)
{
C1FlexDataTree childchild = childRow.UserData as C1FlexDataTree;
foreach (Row childchildRow in childchild.Rows)
{
if (childchildRow.Index > 0)
childchildRow[1] = this.Rows[e.Row][1];
}
}
}
}
}
// Check the level of grid
C1FlexDataTree parent = this;
int level = 0;
while (parent.Parent is C1FlexDataTree)
{
level++;
parent = parent.Parent as C1FlexDataTree;
}
if (level == 0)
{
MessageBox.Show("I am parent");
// Place your code for ParentCellChecked here
}
else if (level == 1)
{
MessageBox.Show("I am parent’s child");
// Place your code for ChildCellChecked here
}
else if (level == 2)
{
MessageBox.Show("I am parent’s child’s child");
// Place your code for ChildChildCellChecked here
}
}
请注意上面的代码段中必须实现 ParentCellChecked , ChildCellChecked 和 ChildChildCellChecked 。
如果我们有父网格的访问权限,也可以访问父网格的孩子的孩子......依此类推。这在下面的代码段中描述。请注意,子网格不能来自创建父网格的类。在DataTree类本身中首选使用此代码段。
if (this.Rows[XthRow].UserData != null)
{
C1FlexDataTree child = this.Rows[e.Row].UserData as C1FlexDataTree;
foreach (Row childRow in child.Rows)
{
if (childRow.Index > 0)
{
// ALL THE CHILD’S ROW
if (childRow.UserData != null)
{
C1FlexDataTree childchild = childRow.UserData as C1FlexDataTree;
foreach (Row childchildRow in childchild.Rows)
{
if (childchildRow.Index > 0)
// ALL THE CHILD’S CHILD’S ROW
}
}
}
}
}