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.選択したセルの行のボトムに赤罫線を描く
        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.エクセルファイルをプロジェクトに参加させ、グリッドに表示する
①エクセルファイルをプロジェクトに参加させる方法
判ってしまえば、そうかとなるのですが・・・
こちらの方々のページを参考にさせて頂きました。↓
  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;
        }
    }

