datagridview-conditional-formatting-performance ソースコード全文

DataGridView_Conditional_Formatting_Performance.sln

DataGridView_Conditional_Formatting_Performance.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.37314.3 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataGridView_Conditional_Formatting_Performance", "DataGridView_Conditional_Formatting_Performance\DataGridView_Conditional_Formatting_Performance.csproj", "{CB0CAC5F-696B-4ED1-B82E-E4F853DEDAAB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CB0CAC5F-696B-4ED1-B82E-E4F853DEDAAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB0CAC5F-696B-4ED1-B82E-E4F853DEDAAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB0CAC5F-696B-4ED1-B82E-E4F853DEDAAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB0CAC5F-696B-4ED1-B82E-E4F853DEDAAB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1BFBE705-FA9D-49E7-B2CE-3537C4B97DDF}
EndGlobalSection
EndGlobal

DataGridView_Conditional_Formatting_Performance/DataGridView_Conditional_Formatting_Performance.csproj

DataGridView_Conditional_Formatting_Performance.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>

DataGridView_Conditional_Formatting_Performance/DataGridView_Conditional_Formatting_Performance.csproj.user

DataGridView_Conditional_Formatting_Performance.csproj.user
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Update="Form1.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

DataGridView_Conditional_Formatting_Performance/Form1.cs

Form1.cs
using System.ComponentModel;
namespace DataGridView_Conditional_Formatting_Performance
{
public partial class Form1 : Form
{
private BindingList<ProductModel> _products = new();
// パフォーマンス対策:使い回すためのスタイルオブジェクトを事前にキャッシュ
private DataGridViewCellStyle _alertStyle = new DataGridViewCellStyle();
private DataGridViewCellStyle _disabledStyle = new DataGridViewCellStyle();
public Form1()
{
InitializeComponent();
InitializeStyles(); // スタイルの事前作成
InitializeDataGridView();
}
// 1. フォーム初期化時に、色やフォントの設定を「一度だけ」生成しておく
private void InitializeStyles()
{
// 在庫切れ時の背景色(薄い赤)
_alertStyle.BackColor = Color.MistyRose;
// 注文不可時の文字色とフォント(グレー・斜体)
_disabledStyle.ForeColor = Color.Gray;
_disabledStyle.Font = new Font(dataGridView1.Font, FontStyle.Italic);
}
private void InitializeDataGridView()
{
// 大量データの読み込みを想定(サンプルデータ)
for (int i = 0; i < 5000; i++)
{
_products.Add(new ProductModel($"P{i:D4}", $"商品データ_{i}", i % 5 == 0 ? 0 : 10, i % 10 == 0 ? "注文不可" : "通常"));
}
dataGridView1.DataSource = _products;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
// イベントの購読
dataGridView1.CellFormatting += DataGridView1_CellFormatting;
}
// 2. 高速に呼び出される描画イベント
private void DataGridView1_CellFormatting(object? sender, DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex < 0 || e.RowIndex >= dataGridView1.Rows.Count) return;
if (dataGridView1.Rows[e.RowIndex].DataBoundItem is ProductModel product)
{
// 条件①:在庫数が 0 の場合(行全体の背景色を変更)
if (product.Stock == 0)
{
// 既存のカラー値をそのまま代入(newしない)
e.CellStyle.BackColor = _alertStyle.BackColor;
}
// 条件②:ステータスが「注文不可」かつ「ステータス」列の場合(セルの文字色・フォントを変更)
var columnName = dataGridView1.Columns[e.ColumnIndex].DataPropertyName;
if (columnName == "Status" && product.Status == "注文不可")
{
// ApplyStyle メソッドを使い、キャッシュしておいたスタイルを丸ごと適用する
e.CellStyle.ApplyStyle(_disabledStyle);
}
}
}
}
}

DataGridView_Conditional_Formatting_Performance/Form1.Designer.cs

Form1.Designer.cs
namespace DataGridView_Conditional_Formatting_Performance
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
dataGridView1 = new DataGridView();
((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit();
SuspendLayout();
//
// dataGridView1
//
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Dock = DockStyle.Fill;
dataGridView1.Location = new Point(0, 0);
dataGridView1.Name = "dataGridView1";
dataGridView1.RowHeadersWidth = 62;
dataGridView1.Size = new Size(800, 450);
dataGridView1.TabIndex = 0;
//
// Form1
//
AutoScaleDimensions = new SizeF(10F, 25F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView1);
Name = "Form1";
Text = "Form1";
((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView1;
}
}

DataGridView_Conditional_Formatting_Performance/Form1.resx

Form1.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

DataGridView_Conditional_Formatting_Performance/ProductModel.cs

ProductModel.cs
namespace DataGridView_Conditional_Formatting_Performance
{
/// <summary>
/// グリッドに表示する商品データを保持するモデルクラスです。
/// </summary>
public class ProductModel
{
/// <summary>
/// 商品コードを取得または設定します。
/// </summary>
public string Code { get; set; }
/// <summary>
/// 商品名を取得または設定します。
/// </summary>
public string Name { get; set; }
/// <summary>
/// 在庫数を取得または設定します。
/// (0 の場合は行全体の背景色を変更する判定に使用します)
/// </summary>
public int Stock { get; set; }
/// <summary>
/// ステータス(通常 / 注文不可 など)を取得または設定します。
/// (「注文不可」の場合はセルの文字色とフォントを変更する判定に使用します)
/// </summary>
public string Status { get; set; }
/// <summary>
/// ProductModel クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="code">商品コード</param>
/// <param name="name">商品名</param>
/// <param name="stock">在庫数</param>
/// <param name="status">ステータス</param>
public ProductModel(string code, string name, int stock, string status)
{
Code = code;
Name = name;
Stock = stock;
Status = status;
}
}
}

DataGridView_Conditional_Formatting_Performance/Program.cs

Program.cs
namespace DataGridView_Conditional_Formatting_Performance
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
}