ComponentOne の DataTree Grid を使用しています。現在、DataTree グリッドには 2 つのレベル (親と子) があります。各グリッドの各行には、ユーザーが行を「選択」できるチェックボックス列があります。ユーザーが親行を選択すると、flexgrid_CellChecked イベントが発生します。子グリッドが選択されると、発生するイベントは flexgrid_ChildCellChecked です。DataTree に 3 番目のレベルを追加し、最も内側のグリッドのチェックボックスが選択されたときに発生する対応するイベントを追加したいと考えています。それを flexgrid_ChildChildCellChecked と呼びましょう。
このイベントは、DataTree クラスの Expand (int row) メソッドでインスタンス化されます。問題は、最初の子 (レベル 2) が展開されるときに、イベント ChildCellChecked および ChildChildCellChecked をハンドラーとして追加できることです。2 番目の子 (レベル 3) が展開されると、これらのイベントは両方とも null になります。
これは、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;
}
2 番目のレベルのグリッドには ChildCellChecked を、3 番目のレベルのグリッドには ChildChildCellChecked というイベントを作成したいと思います。
グリッドは正しく表示されており、展開したり折りたたんだりできます。しかし、第 3 レベルのグリッドでチェックボックスをクリックしても、イベントは発生しません。
イベント ハンドラーを各レベル グリッドに関連付けるにはどうすればよいですか?
アップデート
コード スニペットの 1 つを使用して展開されているレベルを特定すると、レベルが 2 の場合、ChildChildCellChecked イベントは null になります。
第 1 レベルの呼び出し時と第 2 レベルの呼び出し時にメソッド Expand() が呼び出されたときのデバッグ モードでのスクリーン ショットを示すドキュメントを添付しました。
Expand() の最初のレベルの呼び出し中に、ChildCellChecked が作成されます。
Expand() の第 2 レベルの呼び出し中、ChildChildCellChecked は null です。これにより、例外が発生します。
Expand() への 2 番目のレベルの呼び出し中にデリゲート ChildChildCellChecked が null である理由がわかりません。
添付のスクリーン ショットは、エラーをよりよく示すことができます... デバッグ モード中に 2 つのスクリーン ショットを撮ります。
最初のグリッドが拡張されます。これは、親グリッドが最初の子に展開されたときです。両方のイベントが定義されていることがわかります。ChildCellCheck のみが作成されています。
2 番目のグリッドが拡張されます。最初の子グリッドを展開して 2 番目のレベルのグリッドを表示すると、次のエラーが発生します。
実際には、Expand() への最初の呼び出し時に、両方のデリゲートがそれぞれのイベント メソッドに関連付けられます。Expand() の 2 回目の呼び出しでは、両方のデリゲートが null です。
子グリッドが作成されると、レベルに関係なく、その子グリッドのイベント ハンドラーが作成されると考えていました。2 番目のレベルのグリッドに 2 番目のイベント ハンドラーは必要ないということです。チェックボックスがクリックされると、イベントが発生し、イベント メソッド内で、イベントを発生させた子グリッドのレベルを決定できます。
グロリア