🔣

Windows Forms C#定石 - DataGridView - 値依存イメージ表示, ちらつき防止

に公開

はじめに

C# ソフト開発時に、決まり事として実施していた内容を記載します。

DataGridView については下記記事もあります

テスト環境

ここに記載した情報/ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールを Windows 11 24H2 で動作確認しています。

  • Windows Forms - .NET Framework 4.8
  • Windows Forms - .NET 8

値依存イメージ表示

Dev Q&A: DataGridView | Microsoft Learn で、Figure 5 Custom Image Column for the DataGridView として記載されている手法があります。
この手法だと、DataGridViewImageCell 派生クラス( CustomImageCell )に固定イメージを設定しているので、異なるイメージを利用する場合には、別クラスを作成しなければなりません。
そこで、DataGridViewImageColumn 派生クラスにイメージを保持して、イメージを設定可能としています。

// 数値に関係づけられたイメージを表示する DataGridViewCell
public class DataGridViewBindImageColumn : DataGridViewImageColumn
{
  // 初期値を設定しておかないと、意図した動作にならない
  public Image[] BindImages { get; set; } = new Image[] {
                 SystemIcons.Application.ToBitmap() };

  public DataGridViewBindImageColumn()
  {
    this.CellTemplate = new DataGridViewBindImageCell();
    this.ValueType = typeof(int);
    this.ImageLayout = DataGridViewImageCellLayout.Zoom;
    this.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
  }
}
public class DataGridViewBindImageCell : DataGridViewImageCell
{
  public DataGridViewBindImageCell()
  {
    this.ValueType = typeof(int);
  }

  // .NET Framework 時 object? の ? 不要
  protected override object? GetFormattedValue(
    object value, int rowIndex, ref DataGridViewCellStyle cellStyle, 
    TypeConverter valueTypeConverter, 
    TypeConverter formattedValueTypeConverter,
    DataGridViewDataErrorContexts context)
  {
    if (this.OwningColumn is DataGridViewBindImageColumn column
     && column.BindImages != null
     && Value is int index
     && index >= 0 && index < column.BindImages.Length)
    {
      return column.BindImages[index];
    }
    return null;
  }
  // 行追加時の既定値
  public override object DefaultNewRowValue => -1;
}

上記の利用方法を記載します。

// DataGridView 設定
dataGridView1.AllowUserToResizeRows = false;
dataGridView1.AutoGenerateColumns = false;
dataGridView1.MultiSelect = false;            // 複数選択無効
dataGridView1.ColumnHeadersVisible = true;    // 列ヘッダ表示
dataGridView1.RowHeadersVisible = false;      // 行ヘッダ非表示
dataGridView1.AllowUserToDeleteRows = false;  // 削除キーで削除を無効
dataGridView1.AllowUserToAddRows = false;     // 末尾行での行追加を無効
dataGridView1.ScrollBars = ScrollBars.Both;
dataGridView1.ColumnHeadersHeight = 28;

dataGridView1.Columns.AddRange(new DataGridViewColumn[]
{
  new DataGridViewTextBoxColumn { Name = "ID", Width = 30, ReadOnly = true },
  new DataGridViewBindImageColumn { Name = "Default", Width = 50 },
  new DataGridViewBindImageColumn { Name = "Status", Width = 50,
        BindImages = new Image[] {
          SystemIcons.Information.ToBitmap(),
          SystemIcons.Question.ToBitmap(),
          SystemIcons.Warning.ToBitmap(),
          SystemIcons.Error.ToBitmap() } }
});

// テストデータ
dataGridView1.Rows.Clear();
for (int no = 0; no < 5; no++)
{
  DataGridViewRow row = new DataGridViewRow();
  row.CreateCells(dataGridView1);
  row.Height = 30;

  row.Cells[0].Value = no;
  row.Cells[1].Value = no;
  row.Cells[2].Value = no;
  dataGridView1.Rows.Add(row);
}

ちらつき防止

DoubleBuffered

[C#]DataGridViewのDoubleBufferedを有効にする
方法: フォームとコントロールのダブル バッファリングでグラフィックスのちらつきを軽減する

DataGridView を使ってみると、表示が重いことから、ちらつきが気になることがあります。
この表示の重さは、DoubleBuffered プロパティを有効にすることによって、改善が期待できます。
DataGridView では、DoubleBuffered プロパティが protected となってしまっているので直接アクセスできませんが、リフレクションを使用して設定することが可能です。

using System.Reflection;
this.Load += Form1_Load;
// .NET Framework 時 object? の ? 不要
private void Form1_Load(object? sender, EventArgs e)
{
  // デザイナで DataGridView dataGridView1, dataGridView2 を配置
  var info = typeof(DataGridView).GetProperty("DoubleBuffered",
               BindingFlags.Instance | BindingFlags.NonPublic);
  info?.SetValue(dataGridView1, true, null);
  info?.SetValue(dataGridView2, true, null);
}

再描画の一時停止

https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.suspendlayout

https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.resumelayout

DataGirdView のデフォルト動作では、行追加などの操作毎に DataGridView の再描画が発生して、画面がちらついてしまうことがあります。
この対策としては、SuspendLayout と ResumeLayout を使用して再描画を一時停止、再開することで、ちらつきを抑えることができます。

// デザイナで DataGridView dataGridView1 を配置
// 一時停止
Cursor cursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;
dataGridView1.SuspendLayout();

// TODO - データ更新とソート

// 再開
dataGridView1.ResumeLayout();
this.Cursor = cursor;

出典

本記事は、2025/04/10 Qiita 投稿記事の転載です。

Windows Forms C#定石 - DataGridView - 値依存イメージ表示, ちらつき防止

Discussion