0

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 のみが作成されています。 最初の呼び出しで ChildCellChecked イベントに委譲する Expand() 最初の呼び出しで ChildChildCellChecked イベントに委譲する Expand()

2 番目のグリッドが拡張されます。最初の子グリッドを展開して 2 番目のレベルのグリッドを表示すると、次のエラーが発生します。 ChildChildCellChecked デリゲートを割り当てるための Expand() の 2 回目の呼び出し中に例外を示すエラーが発生しました

実際には、Expand() への最初の呼び出し時に、両方のデリゲートがそれぞれのイベント メソッドに関連付けられます。Expand() の 2 回目の呼び出しでは、両方のデリゲートが null です。

子グリッドが作成されると、レベルに関係なく、その子グリッドのイベント ハンドラーが作成されると考えていました。2 番目のレベルのグリッドに 2 番目のイベント ハンドラーは必要ないということです。チェックボックスがクリックされると、イベントが発生し、イベント メソッド内で、イベントを発生させた子グリッドのレベルを決定できます。

グロリア

4

2 に答える 2

0

DataTreeが作成されるたびに、すべての埋め込みグリッド (親オブジェクトの子) が同じイベントを実装することに注意してください。そのため、 ParentCheckChildCheck、およびChildChildCheckイベントをすべて同じDataTreeクラスに作成するのは適切ではありませんでした。これが、DataTree クラスで ParentCheck 、 ChildCheck 、および ChildChildCheck イベントを作成したときにさえChilChildCheckイベント実行する理由です。

CellCheckedイベントが DataTree クラスで作成されると、すべてのグリッドが 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
    }

}

上記のスニペットで、ParentCellCheckedChildCellChecked、および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
                }
            }
        }
    }
}
于 2014-09-05T10:53:15.283 に答える
0

ここにあなたの元の投稿に投稿したように:-

次のコメントを参照してください。

  • ノードが展開されると、親の Controls コレクションに子グリッドが追加されます。同様に、行を折りたたむと、子グリッドは親の Controls コレクションから削除されます。子グリッドを削除すると、子の HeaderGrid の UserData がクリアされます。したがって、イベント ハンドラが完全に無効になります。これが、このスニペットが直接機能しない理由です。

  • 各グリッドにイベントを追加する前にすべての行を展開すると、行ごとに子が 1 つしかない場合に完全に機能します。ただし、これはより一般的なケースでは機能しません。子のイベントが 1 つだけ発生すると、すべての子に対して子のイベントが呼び出されるためです。

  • あなたが実装しようとしたように、最良のシナリオは間違いなく 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 が null かどうかを確認しています。ただし、childGrid の行の UserData は常に null になります。子グリッドがグリッドに追加されるたびに、子グリッドのすべての行が折りたたまれているか、展開できなくなります。

  • ヒント: 行の UserData が null の場合、行が折りたたまれているか、行に childGrid がないことを意味します。

    3 番目のポイントでは、'childs' および 'childs of childs' のイベントを作成しました。これは、親グリッドのイベントを作成しません。したがって、DataTree クラスのコンストラクターにスニペットを追加する必要がある場合があります。

     if (this.ParentGrid == this)
     {
          this.CellChecked+=new RowColEventHandler(Parent_CellChecked);
     }
    

重要:

親グリッド内のすべての子グリッドは DataTree になります。これが、すべての子グリッドの行を展開すると ExpandRow メソッドもトリガーされ、最終的にイベント ハンドラーを追加しようとする理由です。ChildGrid の ExpandRow メソッドが親グリッドのようなイベントを追加しないように、適切な措置を講じてください。これは、childGrid のレベルを確認することで確認できます。これはステップ 3 で実行されます。

于 2014-08-29T05:28:23.843 に答える