none
リレーションをもつ子テーブルの DataGridView で一時的に全リストを表示できるようにするには RRS feed

  • 質問

  • 親子関係にあるテーブル parents, children があり、リレーションを持たせた
    状態で図 (1) のように配置しています。

     

    図中の

    • (A) は親テーブルの内容、
    • (B) と (C) は同じ子テーブルの内容

    を表しています。


    図 (1)

     

     

    図 (1) 右のグリッド (C) で、

    • 親へのリレーションを解き、
    • 既存の BindingSource (註1) を流用して、

    図 (2)-(C) のように出来ないかと考えています (一時的に)。

    (註1)
    ----
    既に parentsBindingSource, childrenBindingSource が DataTable を Form
    にドラッグした際に自動生成されています。


    図 (2)

     

     

     

    図 (2)-(C) は今尋ねている内容が解決したから表示できている訳ではなく、


    Code Snippet
    BindingSource bs = new BindingSource();
    bs.DataMember = "children";
    bs.DataSource = this.database1DataSet; ......................................... (1)
    this.childrenDataGridView1.DataSource = bs;

     

    としてサンプル作成の為に、既存の BindingSource を使わずに表示させています。

    (1) の部分を既存の childrenBindingSource を使い、全アイテムを表示できな
    いかと考えています。

     

    トリッキーな感じがしますが、何か実現できそうな方法はないでしょうか?

    2008年4月5日 5:50

回答

  • そのような機能は無さそうに思います。

    機能が不足しているということではなく、リレーション関係を維持する BindingSource で一時的にリレーション関係を解除する必要性はなさそうに思います。必要であれば子テーブルを直接参照する別の BindingSource を用意しておき、それと切り替えれば良いと思いますので。

     

    と思いつつ、一応調べました。

    前に少し書きましたが、リレーションされた子供のリストは RelatedView が管理しているので、このビューを外部から制御できればと思ってソースを見てみました。しかし、手の届かない IFilter.Invoke でフィルタするようになっていますので、やはり無理そうでした。

     

    さらに一応、トリッキーと思われる要求に対してトリッキーでお薦めしない方法を考えてみました。

    リレーション関係を参照する BindingSource から子テーブルにたどり着き、全データ参照用の BindingSource を一時的に作成します。Tag を使ったり、そのつど作成したりする辺りは、単なる手抜きです。

     

    Code Snippet

    private void Form1_Load(object sender, EventArgs e)
    {
        var dtP = new DataTable("tableP");
        dtP.Columns.Add("pid", typeof(string));
        dtP.Columns.Add("pdata", typeof(string));
        dtP.Rows.Add("p1", "pdata1");
        dtP.Rows.Add("p2", "pdata2");

     

        var dtC = new DataTable("tableC");
        dtC.Columns.Add("cid", typeof(string));
        dtC.Columns.Add("pid", typeof(string));
        dtC.Columns.Add("cdata", typeof(string));
        dtC.Rows.Add("c1", "p1", "cdata1");
        dtC.Rows.Add("c2", "p1", "cdata2");
        dtC.Rows.Add("c3", "p2", "cdata3");

     

        var ds = new DataSet();
        ds.Tables.Add(dtP);
        ds.Tables.Add(dtC);

     

        var rel = new DataRelation(
            "PtoC", dtP.Columns["pid"], dtC.Columns["pid"], false);
        ds.Relations.Add(rel);

     

        var bsP = new BindingSource();
        bsP.DataSource = ds;
        bsP.DataMember = "tableP";

     

        var bsC = new BindingSource();
        bsC.DataSource = bsP;
        bsC.DataMember = "PtoC";

     

        dataGridView1.DataSource = bsP;
        dataGridView2.DataSource = bsC;
    }

     

    private void button1_Click(object sender, EventArgs e)
    {
        if (dataGridView2.Tag == null)
        {
            var bsC = (BindingSource)dataGridView2.DataSource;
            var view = (DataView)bsC.List;
            var rel = view.Table.DataSet.Relations[bsC.DataMember];
            var dtC = rel.ChildColumns[0].Table;

     

            var bsAllC = new BindingSource();
            bsAllC.DataSource = dtC;

     

            dataGridView2.Tag = dataGridView2.DataSource;
            dataGridView2.DataSource = bsAllC;
        }
        else
        {
            var bsAllC = (BindingSource)dataGridView2.DataSource;
            dataGridView2.DataSource = dataGridView2.Tag;
            dataGridView2.Tag = null;
            bsAllC.Dispose();
        }
    }

     

    2008年4月7日 8:31

すべての返信

  • そのような機能は無さそうに思います。

    機能が不足しているということではなく、リレーション関係を維持する BindingSource で一時的にリレーション関係を解除する必要性はなさそうに思います。必要であれば子テーブルを直接参照する別の BindingSource を用意しておき、それと切り替えれば良いと思いますので。

     

    と思いつつ、一応調べました。

    前に少し書きましたが、リレーションされた子供のリストは RelatedView が管理しているので、このビューを外部から制御できればと思ってソースを見てみました。しかし、手の届かない IFilter.Invoke でフィルタするようになっていますので、やはり無理そうでした。

     

    さらに一応、トリッキーと思われる要求に対してトリッキーでお薦めしない方法を考えてみました。

    リレーション関係を参照する BindingSource から子テーブルにたどり着き、全データ参照用の BindingSource を一時的に作成します。Tag を使ったり、そのつど作成したりする辺りは、単なる手抜きです。

     

    Code Snippet

    private void Form1_Load(object sender, EventArgs e)
    {
        var dtP = new DataTable("tableP");
        dtP.Columns.Add("pid", typeof(string));
        dtP.Columns.Add("pdata", typeof(string));
        dtP.Rows.Add("p1", "pdata1");
        dtP.Rows.Add("p2", "pdata2");

     

        var dtC = new DataTable("tableC");
        dtC.Columns.Add("cid", typeof(string));
        dtC.Columns.Add("pid", typeof(string));
        dtC.Columns.Add("cdata", typeof(string));
        dtC.Rows.Add("c1", "p1", "cdata1");
        dtC.Rows.Add("c2", "p1", "cdata2");
        dtC.Rows.Add("c3", "p2", "cdata3");

     

        var ds = new DataSet();
        ds.Tables.Add(dtP);
        ds.Tables.Add(dtC);

     

        var rel = new DataRelation(
            "PtoC", dtP.Columns["pid"], dtC.Columns["pid"], false);
        ds.Relations.Add(rel);

     

        var bsP = new BindingSource();
        bsP.DataSource = ds;
        bsP.DataMember = "tableP";

     

        var bsC = new BindingSource();
        bsC.DataSource = bsP;
        bsC.DataMember = "PtoC";

     

        dataGridView1.DataSource = bsP;
        dataGridView2.DataSource = bsC;
    }

     

    private void button1_Click(object sender, EventArgs e)
    {
        if (dataGridView2.Tag == null)
        {
            var bsC = (BindingSource)dataGridView2.DataSource;
            var view = (DataView)bsC.List;
            var rel = view.Table.DataSet.Relations[bsC.DataMember];
            var dtC = rel.ChildColumns[0].Table;

     

            var bsAllC = new BindingSource();
            bsAllC.DataSource = dtC;

     

            dataGridView2.Tag = dataGridView2.DataSource;
            dataGridView2.DataSource = bsAllC;
        }
        else
        {
            var bsAllC = (BindingSource)dataGridView2.DataSource;
            dataGridView2.DataSource = dataGridView2.Tag;
            dataGridView2.Tag = null;
            bsAllC.Dispose();
        }
    }

     

    2008年4月7日 8:31
  •  TH01 さんからの引用

    そのような機能は無さそうに思います。


    やはりそうなんですか。ソースまでは見ていませんが、BindingSource の仕組
    みを考えたら、無理だろうなぁ、と予想していました。


     TH01 さんからの引用

    リレーション関係を維持する BindingSource で一時的にリレーション関係を解
    除する必要性はなさそうに思います。


    正論です。


     TH01 さんからの引用

    必要であれば子テーブルを直接参照する別の BindingSource を用意しておき、
    それと切り替えれば良いと思いますので。


    実際はそうしていますが、Model クラスの field 数が多くなり、現状あるもの
    だけで何とかならんのか?と思い、BindingSource のイレギュラーな使用を

    試してみましたが、出来なかったのでお尋ねしました。


     TH01 さんからの引用

    と思いつつ、一応調べました。


    ありがとうございます。


     TH01 さんからの引用

    リレーションされた子供のリストは RelatedView が管理しているので、このビュー
    を外部から制御できればと思ってソースを見てみました。しかし、手の届かな
    い IFilter.Invoke でフィルタするようになっていますので、やはり無理そう
    でした。


    残念。

     

     TH01 さんからの引用

    さらに一応、トリッキーと思われる要求に対してトリッキーでお薦めしない方
    法を考えてみました。


    変なこと尋ねまして、済みません。


     TH01 さんからの引用

    リレーション関係を参照する BindingSource から子テーブルにたどり着き、
    全データ参照用の BindingSource を一時的に作成します。

     

    BindingSource から辿 (たど) る....なるほど。参考になります。

     

     

    TH01 さん、サンプルコードありがとうございます。

    2008年4月7日 14:38