6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C# dataGridViewのコツ

Last updated at Posted at 2022-09-08

1.高速化の定石

Form_Loadなどで。
DataGridViewの画面ちらつきをおさえ高速表示するために、DoubleBufferedを有効にする。

// DataGirdViewのTypeを取得
System.Type dgvtype = typeof(DataGridView);
// プロパティ設定の取得
System.Reflection.PropertyInfo dgvPropertyInfo = dgvtype.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
// 対象のDataGridViewにtrueをセットする
dgvPropertyInfo.SetValue(dataGridView1, true, null);

2.データテーブルのセット~書式設定

//件数確保
int 件数 = dt.Rows.Count;
label読込行数.Text = 件数.ToString() + " 行";

//dataGridViewにデータテーブルをセットする。
dataGridView1.DataSource = dt;

//dataGridViewの設定
//ユーザの操作規制 ←これはFormのLoadへ持って行っても良い
dataGridView1.ReadOnly = true;                      //読取専用
dataGridView1.AllowUserToDeleteRows = false;        //行削除禁止
dataGridView1.AllowUserToAddRows = false;           //行挿入禁止
dataGridView1.AllowUserToResizeRows = false;        //行の高さ変更禁止
dataGridView1.RowHeadersVisible = false;            //行ヘッダーを非表示にする
dataGridView1.MultiSelect = false;                  //セル、行、列が複数選択禁止
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;       //セルを選択すると行全体が選択されるようにする

//並び替えができないようにする 【注意】データがセットされた後でしか効かないよ。
foreach (DataGridViewColumn c in dataGridView1.Columns)
    c.SortMode = DataGridViewColumnSortMode.NotSortable;

//コピーモード
dataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;

//基本フォントの設定
dataGridView1.DefaultCellStyle.Font = new System.Drawing.Font("MS UI Gothic", 10);

//ヘッダーの色等
dataGridView1.EnableHeadersVisualStyles = false;     // Visualスタイルを使用しない
dataGridView1.ColumnHeadersDefaultCellStyle.BackColor = Color.LightGray;
dataGridView1.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("MS UI Gothic", 9);
dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
//ヘッダ高さ
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
dataGridView1.ColumnHeadersHeight = 30;

//ヘッダー名称変更
dataGridView1.Columns["住所1"].HeaderCell.Value = "県名";

//カラム幅設定
dataGridView1.Columns[0].Width = 50;     //社員番号
dataGridView1.Columns[1].Width = 100;    //カラム名
dataGridView1.Columns[2].Width = 70;     //カラム名
dataGridView1.Columns[3].Width = 70;     //カラム名
dataGridView1.Columns[4].Width = 70;     //カラム名
dataGridView1.Columns[5].Width = 80;     //カラム名

//寄せ
dataGridView1.Columns["社員番号"].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;

//数値を3けた区切
dataGridView1.Columns["金額"].DefaultCellStyle.Format = "#,0";

//小数第2位まで表示するだけ
dataGridView1.Columns["増加率"].DefaultCellStyle.Format = "N2";

//小数第2位まで表示して、”%”を加える。
dataGridView1.Columns["増加率"].DefaultCellStyle.Format = @"#,##0.00%";

//列指定の太字
dataGridView1.Columns["社員番号"].DefaultCellStyle.Font = new Font(dataGridView1.Font, FontStyle.Bold);


//値取得2種(値2の方が可読性が良いかな?)   
string 1 = dataGridView1[2, 4].Value.ToString();  //【注意】[col,row] の順。 行列は0始まり。
string 2 = dataGridView1.Rows[0].Cells["社員番号"].Value.ToString();

3..DataSource から DataTble へ値を渡す。

            //参照渡し
            DataTable dt1 = new DataTable();
            dt1 = (DataTable)dataGridView1.DataSource;

            //値渡し
            DataTable dt2 = new DataTable();
            dt2 = ((DataTable)dataGridView1.DataSource).Copy() ;

4.セルの値によって行の色を変更する。

        private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            //セルの値によって行のバックカラーを変更する。
            DataGridView dgv = (DataGridView)sender;

            //セルの列を確認
            if (dgv.Columns[e.ColumnIndex].Name == "許可" && e.Value.ToString() == "不可")
            {   
                //単一セルのみ
                e.CellStyle.BackColor = Color.Violet;
                //対象行
                dgv.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightGray;
            }
            if (dgv.Columns[e.ColumnIndex].Name == "許可" && e.Value.ToString() == "")
            {   
                //そうでない場合は戻す
                //単一セルのみ
                e.CellStyle.BackColor = Color.White;
                //対象行
                dgv.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
            }
        }

5.チェックボックス型セルの値確定タイミング

dataGridViewのチェックボックス型セルをクリックして、trueになった瞬間(チェックマークが表示された瞬間)に他の動作を起こしたかったが、どうしても実装できなかった。

ネットで教えてもらったのは…
「チェックマークが表示されていも内部の値は変らない、次のセルを選択した際にそれが確定される。チェックマークが表示/非表示された瞬間に値(true/false)を確定させるには、DataGridView.CommitEdit を呼ぶ必要がある」ということだった。
あのチェックマークは見えてるだけなんや~
そんなん判らんでぇ…(TT)…サンプルは以下の通り。

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    // 0番目がチェックボックス型の列として、これだけを処理対象とする
    if (dataGridView1.CurrentCell.ColumnIndex != 0) return;

    // 値を確定する!!!
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    //ここに、すぐさま起こしたいコードを書く
}

6.選択したセルの行のボトムに赤罫線を描く

選択セルの行に赤線.png

        int widthAllCol = 0; //各カラム幅の合計値
        //private int prevSelectRow = -1;

        private void Form1_Load(object sender, EventArgs e)
        {
            // DataTableの個所は「猫の気ままなC#日記」さんのコードを利用させてもらってます。
            // ありがとうございます。

            DataTable dt = new DataTable("Table1");
            string[] id = { "S0001", "S0002", "S0003", "S0004", "S0005", "S0006" };
            string[] name = { "あんぱん", "メロンパン", "カレーパン", "いちごじゃむパン", "チョココロネ", "クロワッサン" };
            string[] value = { "100", "105", "110", "115", "120", "125" };

            // DataTableに列を追加します。
            dt.Columns.Add("商品番号");
            dt.Columns.Add("商品名");
            dt.Columns.Add("価格");

            // DataTableにデータを格納します。
            for (int i = 0; i < 5; i++)
            {
                dt.Rows.Add(dt.NewRow());
                dt.Rows[i]["商品番号"] = id[i];
                dt.Rows[i]["商品名"] = name[i];
                dt.Rows[i]["価格"] = value[i];
            }

            //dataGridView1に表示
            dataGridView1.DataSource = dt;

            //dataGridView1の基本設定
            dataGridView1.ReadOnly = true;                      //読取専用
            dataGridView1.AllowUserToDeleteRows = false;        //行削除禁止
            dataGridView1.AllowUserToAddRows = false;           //行挿入禁止
            dataGridView1.AllowUserToResizeRows = false;        //行の高さ変更禁止
            dataGridView1.RowHeadersVisible = false;            //行ヘッダーを非表示にする
            dataGridView1.MultiSelect = true;                  //セル、行、列が複数選択禁止
            //dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;       //セルを選択すると行全体が選択されるようにする

            //ここで全カラム幅を計算する!
            widthAllCol = 0;
            for (int i = 0; i < dataGridView1.ColumnCount; i++)
            {
                widthAllCol += dataGridView1.Columns[i].Width;    //各カラム幅の合計値
            }
        }


        private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;

            Pen penRed = new Pen(Color.Red, 2);
            Pen penOriginal = new Pen(SystemColors.ControlDark, 1);     //デフォルトの罫線の色

            if (e.RowIndex == dgv.CurrentRow.Index)
            {
                //オリジナルコード
                //参考にさせて頂いた先
                //http://ssk-development.blogspot.com/2017/09/datagridview_5.html
                //https://tt195361.hatenablog.com/entry/2015/05/22/164840
                //int startX = dgv.RowHeadersVisible ? dgv.RowHeadersWidth : 0;
                //int startY = e.RowBounds.Top + 1;
                //int endX = startX + dgv.Columns.GetColumnsWidth(DataGridViewElementStates.Visible) - dgv.HorizontalScrollingOffset;

                int startX = 0; 
                int startY = e.RowBounds.Top + e.RowBounds.Height - 1; 
                int endX = widthAllCol; 

                e.Graphics.DrawLine(penRed,
                                    startX,
                                    startY,
                                    endX,
                                    startY);
            }
            else
            {
                int startX = 0;
                int startY = e.RowBounds.Top + e.RowBounds.Height - 1;
                int endX = widthAllCol;

                e.Graphics.DrawLine(penOriginal,
                                    startX,
                                    startY,
                                    endX,
                                    startY);
            }
        }


        private void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;

            widthAllCol = 0;
            for (int i = 0; i < dgv.ColumnCount; i++)
            {
                widthAllCol += dgv.Columns[i].Width;    //各カラム幅の合計値
            }
            
            //全面か1行づつは、処理速度見ながら判断のこと
            //書き直し(全面)
            dataGridView1.Invalidate();
            
            //書き直し(1行づつ)
            //if (prevSelectRow != -1) dataGridView1.InvalidateRow(prevSelectRow);
            //if (dataGridView1.SelectedCells.Count != 0)
            //{
            //    prevSelectRow = dataGridView1.SelectedCells[0].RowIndex;
            //    dataGridView1.InvalidateRow(prevSelectRow);
            //}
        }

7.エクセルファイルをプロジェクトに参加させ、グリッドに表示する

エクセル参加.png

①エクセルファイルをプロジェクトに参加させる方法
判ってしまえば、そうかとなるのですが・・・
こちらの方々のページを参考にさせて頂きました。↓
  http://kanesuzu-san.com/visualstudio-file-tsuika
  https://raishin.xyz/post-201/

②エクセルファイルをdataGridView1.DataSourceに設定する方法
   対象ファイル:エクセル2013の.xlsxファイル
 【注意】エクセルのバージョンによって、設定値が異なります。
 参考にさせて頂いたページ↓
  https://qiita.com/unarist/items/6cc35bb9fe502ced332f

            System.Data.OleDb.OleDbConnection MyConnection;
            System.Data.DataSet DtSet;
            System.Data.OleDb.OleDbDataAdapter MyCommand;
            MyConnection = new System.Data.OleDb.OleDbConnection(@"provider=Microsoft.ACE.OLEDB.15.0;Data Source='..\..\元データ.xlsx';Extended Properties=Excel 8.0;");
            MyCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [Sheet1$]", MyConnection);
            MyCommand.TableMappings.Add("Table", "TestTable");
            DtSet = new System.Data.DataSet();
            MyCommand.Fill(DtSet);
            dataGridView1.DataSource = DtSet.Tables[0];
            MyConnection.Close();

8.データベース問合せ結果を一発でグリッドに表示する。

            using (SqlConnection connection = new SqlConnection(DB接続文字列)
            using (var command = connection.CreateCommand())
            {
                try
                {
                    // データベースの接続開始
                    connection.Open();

                    string SQL ="select ...";

                    // SQLの設定
                    command.CommandText = SQL;

                    // SQLの実行
                    var adapter = new SqlDataAdapter(command);
                    adapter.Fill(dt);
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message);
                    throw;
                }
                finally
                {
                    // データベースの接続終了
                    connection.Close();
                }
            }

            dataGridView1.DataSource = dt;

9.グリッドにドラッグしたファイルを読み込む

[準備] フォーム上にDataGridViewとTextBoxを配置する。

        private void dataGridView1_DragDrop(object sender, DragEventArgs e)
        {
            //【リセット!】↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
            //表示系のリセットが必要ならここで実施
            

            //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            for (int i = 0; i < files.Length; i++)
            {
                string fileName = files[i];
                textBoxドロップパス.Text = fileName;
            }
        }


        private void dataGridView1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

[Sheet1]シートのデータを読み込む

    private void textBoxドロップパス_TextChanged(object sender, EventArgs e)
    {
        int errorRow = 0;
        string error = "無"; //有無

        //[準備1]Textが空白なら中止-------------------------------------------------------------------------------
        if (textBoxドロップパス.Text == "")
        {
            return;
        }

        //1)エクセル読み込み-------------------------------------------------------------------------------------
        //ht[参考]tps://www.ipentec.com/document/csharp-open-read-excel-book-and-sheet

        //改行記号を削除して代入
        string ExcelBookFileName = textBoxドロップパス.Text.Replace(Environment.NewLine, "");
        ExcelBookFileName = ExcelBookFileName.Replace("\\", "\\\\");

        //Console.WriteLine("加工後:" + ExcelBookFileName);

        //DataTbleの準備
        System.Data.DataTable dt = new System.Data.DataTable();
        DataRow dr;

        //年月日のDistinctを求める為のDictionary
        var dic年月日 = new Dictionary<string, string>();  //Key:年月日, Value:年月日 

        //DataTableカラム追加/定義
        dt.Columns.Add("社員番号", typeof(string));
        dt.Columns.Add("氏名", typeof(string));
        dt.Columns.Add("性別", typeof(string));

       //これからエクセル読み込み!

        var excelApplication = new Microsoft.Office.Interop.Excel.Application();
        try
        {
            Workbooks workbooks = excelApplication.Workbooks;
            try
            {
                Workbook workbook = workbooks.Open(ExcelBookFileName);
                try
                {
                    Sheets worksheets = workbook.Sheets;
                    try
                    {

                        //Worksheet worksheet = worksheets[1];   
                        //の様に番号でしかシートを指定できないので↓↓↓

                        //1) シート名からシートインデックスを探す(一発の関数は無いみたい(TT))
                        int sheetId = -1;
                        int m = 0;
                        foreach (Worksheet sh in worksheets)
                        {
                            Console.WriteLine("-----m:" + m.ToString() + " / " + sh.Name);
                            m += 1;
                            if (sh.Name == "Sheet1")
                            {
                                sheetId = m;
                            }
                        }
                        if (sheetId == -1)
                        {
                            MessageBox.Show("[Sheet1]シートが見つかりません。\n前後に半角スペース等が入っていませんか?\n確認ください。");
                        }

                        //2) 対象シートを読込む
                        Worksheet worksheet = worksheets[sheetId];   //読込対象のシートを指定!!! 
                        try
                        {
                            // 使用範囲を一括で二次元配列にコピー
                            Console.WriteLine("-----これから[使用範囲を一括で二次元配列にコピー]");
                            Object[,] rangeArray;
                            Range usedRange = worksheet.UsedRange;
                            try
                            {
                                rangeArray = usedRange.Value;
                            }
                            finally
                            {
                                Marshal.ReleaseComObject(usedRange);
                            }

                            //Console.WriteLine("-----これから[(テスト)配列の並び確認]");
                            //(テスト)配列の並び確認
                            //Console.WriteLine("rangeArray[5,2].ToString(): " + rangeArray[5, 2].ToString());


                            //(テスト) 配列要素のNull判別の方法
                            // rangeArray[2, 1].ToString()); の元ファイルは空白、配列化するとNullが入入る。
                            //if (rangeArray[2, 1] == null)
                            //{
                            //    Console.WriteLine("Nullです。");
                            //}
                            //else
                            //{
                            //    Console.WriteLine("Nullではありません。");
                            //}


                            //2次元配列の長さ
                            int lastRow = rangeArray.GetLength(0);   //1次元
                            int lastCol = rangeArray.GetLength(1);   //2次元

                            Console.WriteLine("lastRow:" + lastRow);
                            Console.WriteLine("lastCol:" + lastCol);

                            //更新日時取得
                            DateTime 更新日時 = DateTime.Now;

                            // 二次元配列をループを回しながらdtに格納する。
                            //ヘッダー無し int i = 0;
                            //ヘッダーあり int i = 1;
                            for (int i = 0; i < lastRow; i++)
                            {
                                //Console.WriteLine("i:" + i.ToString());
                                errorRow = i + 1;

                                dr = dt.NewRow();

                                if (rangeArray[1 + i, 1] == null)
                                {
                                    dr["社員番号"] = "";
                                }
                                else
                                {
                                    dr["社員番号"] = rangeArray[1 + i, 1].ToString();
                                }

                                if (rangeArray[1 + i, 2] == null)
                                {
                                    dr["氏名"] = "";
                                }
                                else
                                {
                                    dr["氏名"]     = rangeArray[1 + i, 2].ToString();
                                }

                                if (rangeArray[1 + i, 3] == null)
                                {
                                    dr["性別"] = "";
                                }
                                else
                                {
                                    dr["性別"]     = rangeArray[1 + i, 3].ToString();
                                }

                                dt.Rows.Add(dr);
                            }
                        }
                        finally
                        {
                            Marshal.ReleaseComObject(worksheet);
                            Console.WriteLine("---------------【完了】Marshal.ReleaseComObject(worksheet);");
                        }
                    }
                    catch
                    {
                        error = "有";
                        MessageBox.Show("ファイルの読み込みに失敗しました。" +
                                                errorRow.ToString() + "行目のデータに問題があります。" +
                                                "[catch/worksheet]");
                    }
                    finally
                    {
                        Marshal.ReleaseComObject(worksheets);
                        Console.WriteLine("---------------【完了】Marshal.ReleaseComObject(worksheets);");
                    }
                }
                finally
                {
                    if (workbook != null)
                    {
                        workbook.Close(false);
                    }
                    Marshal.ReleaseComObject(workbook);
                    Console.WriteLine("---------------【完了】Marshal.ReleaseComObject(workbook);");
                }
            }
            finally { Marshal.ReleaseComObject(workbooks); }
        }
        catch
        {
            error = "有";
        }
        finally
        {
            if (excelApplication != null)
            {
                excelApplication.Quit();
            }
            Marshal.ReleaseComObject(excelApplication);
            Console.WriteLine("---------------【完了】Marshal.ReleaseComObject(excelApplication);");
        }

        if (error == "有")
        {
            Console.WriteLine("ファイルの読込に失敗しました。");
            return;
        }


        //2.dataGridView1への登録と設定-----------------------------------------------------------------------------
        //dataGridView1にセットする。
        dataGridView1.DataSource = dt;

        //dataGridView1の設定
        //ユーザの操作規制 ←これはFormのLoadへ持って行っても良い
        dataGridView1.ReadOnly = true;                      //読取専用
        dataGridView1.AllowUserToDeleteRows = false;        //行削除禁止
        dataGridView1.AllowUserToAddRows = false;           //行挿入禁止
        dataGridView1.AllowUserToResizeRows = false;        //行の高さ変更禁止              
        dataGridView1.RowHeadersVisible = false;            //行ヘッダーを非表示にする
        dataGridView1.MultiSelect = false;                  //セル、行、列が複数選択禁止
        dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;       //セルを選択すると行全体が選択されるようにする

        //並び替えができないようにする
        foreach (DataGridViewColumn c in dataGridView1.Columns)
            c.SortMode = DataGridViewColumnSortMode.NotSortable;

        //基本フォントの設定
        dataGridView1.DefaultCellStyle.Font = new System.Drawing.Font("MS UI Gothic", 10);

        //ヘッダーの色等
        dataGridView1.EnableHeadersVisualStyles = false;              // Visualスタイルを使用しない
        dataGridView1.ColumnHeadersDefaultCellStyle.BackColor = Color.LightGray;
        dataGridView1.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("MS UI Gothic", 9);
        dataGridView1.ColumnHeadersHeight = 20;
        dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

        //カラム幅設定
        dataGridView1.Columns["社員番号"].Width = 80;
        dataGridView1.Columns["氏名"].Width = 250;
        dataGridView1.Columns["性別"].Width = 250;

        //読み込まないRowをグレーにする(ここではシート上の3行目からデータ部が始まるとする)
        for (int i = 0; i < 3 - 1; i++)
        {
            dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Gainsboro;
        }
    }

6
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?