1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2025-04-10

はじめに

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

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

テスト環境

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

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

記載したソースコードは .NET 8 ベースとしています。
.NET Framework 4.8 の場合は、コメントで記載している null 許容参照型の明示 ? を削除してください。

Visual Studio 2022 - .NET Framework 4.8 は、C# 7.3 が既定です。
このため、サンプルコードは、C# 7.3 機能範囲で記述しています。

値依存イメージ表示

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);
}

DataGirdView-Image.png

ちらつき防止

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);
}

下記手法で Form 全体をダブルバッファリングさせることもできますが、複雑な UI を描画する際にはパフォーマンスに影響を与える可能性があります。

// 対象 Form クラスに追加
protected override CreateParams CreateParams
{
  get
  {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED 追加
    return cp;
  }
}

再描画の一時停止

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

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

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

// 再開
dataGridView1.ResumeLayout();
this.Cursor = cursor;
1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?