none
Fillしバインドした列とDataGridViewのColumns.Addで初期化した列の関連付け RRS feed

  • 質問

  • お世話になっております。
    初歩的なことかと思いますがどうか宜しくお願い致します。

    VS2008Express C#,SQLServer2008です。


    あるテーブルからデータをFillしてバインドオブジェクトと関連付け、
    それをDataGridViewのDataSourceに設定しました。


    そのままですと、Fillする際のSelect文で指定した列名、ならびに
    データが表示されますが、この時の列名でなく
    DataGridViewのColumns.Addで指定した列名を使いたいのです(関連付けると言ったが適切でしょうか)。
    それもSQLの別名(select hoge as ほげ)ではなく。


    現状、以下のように記述しますと、Fillしてきた列の横にColumns.Addした列が「追加」されてしまいます。
    要するに、4列表示するべきが8列になってしまいます。
    列が追加でセットされてしまうわけです。


    かといって、this.MyDataGrid.DataSource = binding;
    の前にInitGrid();で初期化しても行数だけでデータが表示されません。
    セルが全て空白の状態です。


    どのようにすれば、Fillしバインドした列名とColumns.Addした列を関連付け出来ますでしょうか?

        public Form1()
        {
          InitializeComponent();
    
          string con ="localhost・・・・";
    
          string queryString = "SELECT 見積伝票キー,表示順,取引内訳区分 ,商品キー FROM dbo.見積明細";
    
          adapter = new SqlDataAdapter(queryString, con);
    
          ds = new DataSet();
          adapter.Fill(ds, "見積明細");
    
    
          //データセットとバインドオブジェクトをバインド
          binding = new BindingSource();
          binding.DataMember = "見積明細";
          binding.DataSource = ds;
    
          //↓先に初期化しても全行空白になる
          //InitGrid(); 
    
          //グリッドとバインドオブジェクトをバインド
          this.MyDataGrid.DataSource = binding;
    
          //列の追加になってしまう
          InitGrid(); 
    
        }
    
    
        private void InitGrid()
        {
          //Columnの自動生成をキャンセル
          this.MyDataGrid.AutoGenerateColumns = false;
    
          this.MyDataGrid.Columns.Add("見積伝票キー", "コードから追加した列1");
          this.MyDataGrid.Columns.Add("表示順", "コードから追加した列2");
          this.MyDataGrid.Columns.Add("取引内訳区分", "コードから追加した列3");
          this.MyDataGrid.Columns.Add("商品キー", "コードから追加した列4");
    
          
          
    
        }

    2010年7月7日 8:45

回答

  • 以下のように実行した場合ですが、

     

    // DBからデータを取得
    System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection();
    cn.ConnectionString = "XXXXXXXXXXXX";
    cn.Open();
    System.Data.SqlClient.SqlCommand sc = new System.Data.SqlClient.SqlCommand("select * From hoge", cn);
    System.Data.SqlClient.SqlDataAdapter ad = new System.Data.SqlClient.SqlDataAdapter(sc);
    System.Data.DataTable dt = new System.Data.DataTable();
    ad.Fill(dt);
    cn.Close();
    cn.Dispose();
    
    // DataGridViewにDataTableをデータバインド
    this.dataGridView1.DataSource = dt;
    
    // DataGridViewにカラムを追加
    this.dataGridView1.AutoGenerateColumns = false;
    this.dataGridView1.Columns.Add("見積伝票キー", "コードから追加した列1");
    this.dataGridView1.Columns.Add("表示順", "コードから追加した列2");
    this.dataGridView1.Columns.Add("取引内訳区分", "コードから追加した列3");
    this.dataGridView1.Columns.Add("商品キー", "コードから追加した列4");
    

     

    DataSourceでデータバインドした範囲は、取得したDataTableのカラムの範囲までとなります。

    よって、データバインド後にColumns.Addでカラムを追加しても、データバインドデータの末尾に列が追加されるだけで、

    そのカラムはデータバインドの範囲外のカラムになります。

    DataGridViewに表示された、Columns.Addで追加していない列までがデータバインド、それ以降はデータバインド外です。

    なのでデバッガでブレイクしてみるとわかりますが、上記コードの後でDataSourceの中身を見ても、追加カラムは含まれません。

     

    なお、上記コードの末尾に

     

    this.dataGridView1.Rows.Add

     

    を行った場合、データバインドされている場合はコードでの行追加はできない、みたいな例外が出ると思います。

    つまり、列追加はしていいけど、それはデータバインドとしては扱わない、行追加はデータバインド列とそうじゃない列が

    混在するし、そもそもデータバインドしてる場合はDataSourceに対して行追加を行う、ということになります。

     

    では、DataGridViewのカラムに対して、ヘッダテキストを設定してみると

     

    this.dataGridView1.Columns[0].HeaderText = "コードから追加した列1";
    this.dataGridView1.Columns[0].Name = "見積伝票キー";
    

     

    画面表示でDataGridViewを見ると、一見正しく表示されたように見えます。

    しかし、デバッガでDataSourceを見てみると、中身は古いヘッダテキスト(DBから取得した時の情報)のままです。

    これは、表示自体はDataSourceの内容だけど、DataGridViewのColumnの設定でヘッダテキストが設定された

    ので、表示上は設定されたヘッダテキストを使うけど、実際のDataSourceは変わらないということになります。

     

    データバインドを使う際は、以下のようにデータバインドとコードでの設定が混在しないよう、

    データバインドしたDataTableのColumn定義自体を設定する方法が、表示と実際のデータの中身の統一ができます。

     

    ad.Fill(dt);
    cn.Close();
    cn.Dispose();
    
    dt.Columns[0].ColumnName = "見積伝票キー";
    
    this.dataGridView1.DataSource = dt;

     

    今回の場合、ただヘッダテキストの文字列を任意に変更したいだけであれば、

    this.dataGridView1.Columns[0].HeaderText = "コードから追加した列1";
    でよいと思います。

     


    • 編集済み honefai 2010年7月7日 9:54 追記
    • 回答としてマーク sumi_sumi 2010年7月7日 15:49
    2010年7月7日 9:42
  • 列ごとにDataPropertyNameプロパティにDataTableの列名、HeaderTextプロパティに表示したい列名を設定すればOKです。デザイナからDataGridViewの右上にある小さな三角(スマートタググリフ)をクリックして「列の編集」でも設定することができます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sumi_sumi 2010年7月7日 15:49
    2010年7月7日 14:26
    モデレータ

すべての返信

  • 以下のように実行した場合ですが、

     

    // DBからデータを取得
    System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection();
    cn.ConnectionString = "XXXXXXXXXXXX";
    cn.Open();
    System.Data.SqlClient.SqlCommand sc = new System.Data.SqlClient.SqlCommand("select * From hoge", cn);
    System.Data.SqlClient.SqlDataAdapter ad = new System.Data.SqlClient.SqlDataAdapter(sc);
    System.Data.DataTable dt = new System.Data.DataTable();
    ad.Fill(dt);
    cn.Close();
    cn.Dispose();
    
    // DataGridViewにDataTableをデータバインド
    this.dataGridView1.DataSource = dt;
    
    // DataGridViewにカラムを追加
    this.dataGridView1.AutoGenerateColumns = false;
    this.dataGridView1.Columns.Add("見積伝票キー", "コードから追加した列1");
    this.dataGridView1.Columns.Add("表示順", "コードから追加した列2");
    this.dataGridView1.Columns.Add("取引内訳区分", "コードから追加した列3");
    this.dataGridView1.Columns.Add("商品キー", "コードから追加した列4");
    

     

    DataSourceでデータバインドした範囲は、取得したDataTableのカラムの範囲までとなります。

    よって、データバインド後にColumns.Addでカラムを追加しても、データバインドデータの末尾に列が追加されるだけで、

    そのカラムはデータバインドの範囲外のカラムになります。

    DataGridViewに表示された、Columns.Addで追加していない列までがデータバインド、それ以降はデータバインド外です。

    なのでデバッガでブレイクしてみるとわかりますが、上記コードの後でDataSourceの中身を見ても、追加カラムは含まれません。

     

    なお、上記コードの末尾に

     

    this.dataGridView1.Rows.Add

     

    を行った場合、データバインドされている場合はコードでの行追加はできない、みたいな例外が出ると思います。

    つまり、列追加はしていいけど、それはデータバインドとしては扱わない、行追加はデータバインド列とそうじゃない列が

    混在するし、そもそもデータバインドしてる場合はDataSourceに対して行追加を行う、ということになります。

     

    では、DataGridViewのカラムに対して、ヘッダテキストを設定してみると

     

    this.dataGridView1.Columns[0].HeaderText = "コードから追加した列1";
    this.dataGridView1.Columns[0].Name = "見積伝票キー";
    

     

    画面表示でDataGridViewを見ると、一見正しく表示されたように見えます。

    しかし、デバッガでDataSourceを見てみると、中身は古いヘッダテキスト(DBから取得した時の情報)のままです。

    これは、表示自体はDataSourceの内容だけど、DataGridViewのColumnの設定でヘッダテキストが設定された

    ので、表示上は設定されたヘッダテキストを使うけど、実際のDataSourceは変わらないということになります。

     

    データバインドを使う際は、以下のようにデータバインドとコードでの設定が混在しないよう、

    データバインドしたDataTableのColumn定義自体を設定する方法が、表示と実際のデータの中身の統一ができます。

     

    ad.Fill(dt);
    cn.Close();
    cn.Dispose();
    
    dt.Columns[0].ColumnName = "見積伝票キー";
    
    this.dataGridView1.DataSource = dt;

     

    今回の場合、ただヘッダテキストの文字列を任意に変更したいだけであれば、

    this.dataGridView1.Columns[0].HeaderText = "コードから追加した列1";
    でよいと思います。

     


    • 編集済み honefai 2010年7月7日 9:54 追記
    • 回答としてマーク sumi_sumi 2010年7月7日 15:49
    2010年7月7日 9:42
  • 列ごとにDataPropertyNameプロパティにDataTableの列名、HeaderTextプロパティに表示したい列名を設定すればOKです。デザイナからDataGridViewの右上にある小さな三角(スマートタググリフ)をクリックして「列の編集」でも設定することができます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sumi_sumi 2010年7月7日 15:49
    2010年7月7日 14:26
    モデレータ
  • honefaiさま
    有難う御座います。

    データバインドの範囲外のカラムになるからこのような結果だったのですね。
    知りませんでした。
    大変勉強になりました。

    末尾にthis.dataGridView1.Rows.Addを行うと確かに例外が出ました。

    詳細で分かりやすい解説本当に有難う御座います。




    trapemiyaさま
    有難う御座います。
    DataPropertyNameプロパティ知りませんでした。
    やりたいことが実現出来ました。
    本当に有難う御座います。

    グリッドの中にDataGridViewComboBoxColumnも使いたいので調べながら頑張ってみます。

    有益な情報いつも有難う御座います。
    2010年7月7日 15:55