Windows フォーム DataGridView コントロールを拡張するための推奨される手順
DataGridView コントロールは、最大限のスケーラビリティを達成するように設計されています。 大量のデータを表示する必要がある場合は、このトピックで説明するガイドラインに従って、大量のメモリを消費したり、ユーザー インターフェイス (UI) の応答性が低下したりしないようにする必要があります。 このトピックでは、以下の問題について説明します。
セル スタイルの効率的な使用
ショートカット メニューの効率的な使用
自動サイズ変更の効率的な使用
選択したセル、行、列のコレクションの効率的な使用
共有行の使用
行が非共有にならないようにする
特別なパフォーマンスが必要な場合は、仮想モードを実装して、独自のデータ管理操作を行うことができます。 詳細については、「Windows フォーム DataGridView コントロールでのデータ表示モード」を参照してください。
セル スタイルの効率的な使用
各セル、行、列には、それぞれスタイル情報を持たせることができます。 スタイル情報は DataGridViewCellStyle オブジェクトに格納されます。 個々の多数の DataGridView 要素に対してセル スタイル オブジェクトを作成することは、特に大量のデータを扱う場合には非効率的である可能性があります。 パフォーマンスへの影響を避けるには、次のガイドラインに従ってください。
個々の DataGridViewCell または DataGridViewRow オブジェクトにセル スタイル プロパティを設定することは避けてください。 これには RowTemplate プロパティで指定された行オブジェクトも含まれます。 行テンプレートから複製された新しい各行は、テンプレートのセル スタイル オブジェクトの独自のコピーを受け取ります。 スケーラビリティを最大限に高めるには、セル スタイルのプロパティを DataGridView レベルで設定します。 たとえば、DataGridViewCell.Style プロパティではなく DataGridView.DefaultCellStyle プロパティを設定します。
一部のセルで既定の形式以外の形式が必要な場合は、セルのグループ、行、または列全体で同じ DataGridViewCellStyle インスタンスを使用します。 個々のセル、行、列に DataGridViewCellStyle 型のプロパティを直接設定することは避けてください。 セル スタイルの共有の例については、「方法: Windows フォーム DataGridView コントロールの既定のセル スタイルを設定する」を参照してください。 また、CellFormatting イベント ハンドラーを処理することで、セル スタイルを個別に設定する際にパフォーマンスの低下を回避することができます。 例については、「方法: Windows フォーム DataGridView コントロールのデータの書式設定をカスタマイズする」を参照してください。
セルのスタイルを決定する際には、DataGridViewCell.Style プロパティではなく DataGridViewCell.InheritedStyle プロパティを使用します。 Style プロパティにアクセスすると、そのプロパティがまだ使用されていない場合、DataGridViewCellStyle クラスの新しいインスタンスが作成されます。 また、一部のスタイルが行、列、またはコントロールから継承されている場合、このオブジェクトにはセルの完全なスタイル情報が含まれていない可能性があります。 セル スタイルの継承の詳細については、「Windows フォーム DataGridView コントロールでのセルのスタイル」を参照してください。
ショートカット メニューの効率的な使用
各セル、行、列にはそれぞれショートカット メニューを設定できます。 DataGridView コントロールのショートカット メニューは ContextMenuStrip コントロールで表されます。 セル スタイル オブジェクトと同様に、個々の DataGridView 要素に多数のショートカット メニューを作成すると、パフォーマンスに悪影響を及ぼします。 このペナルティを回避するには、次のガイドラインに従ってください。
個々のセルと行に対してショートカット メニューを作成することは避けてください。 これには、コントロールに新しい行が追加されたときにショートカット メニューと共に複製される行テンプレートも含まれます。 スケーラビリティを最大限に高めるには、コントロールの ContextMenuStrip プロパティのみを使用して、コントロール全体に 1 つのショートカット メニューを指定します。
複数の行やセルに対して複数のショートカット メニューが必要な場合は、CellContextMenuStripNeeded または RowContextMenuStripNeeded イベントを処理します。 これらのイベントを使用すると、ショートカット メニューのオブジェクトを自分で管理して、パフォーマンスを調整することができます。
自動サイズ変更の効率的な使用
行、列、ヘッダーは、セルの内容が変化すると自動的にサイズが変更され、セルの内容全体がクリッピングされることなく表示されます。 サイズ設定モードを変更して、行、列、およびヘッダーのサイズを変更することもできます。 正しいサイズを決定するために、DataGridView コントロールを使用して、収容しなければならない各セルの値を調べる必要があります。 大規模なデータセットを扱う場合、自動サイズ変更が発生すると、この分析がコントロールのパフォーマンスに悪影響を与える可能性があります。 パフォーマンスが低下しないようにするには、次のガイドラインに従ってください。
行数の多い DataGridView コントロールでは、自動サイズ設定を使用しないでください。 自動サイズ設定を使用する場合は、表示されている行に基づいてのみサイズを変更します。 仮想モードでも、表示されている行のみを使用します。
行と列には、DataGridViewAutoSizeRowsMode、DataGridViewAutoSizeColumnsMode、DataGridViewAutoSizeColumnMode 列挙型の
DisplayedCells
またはDisplayedCellsExceptHeaders
フィールドを使用します。行のヘッダーには、DataGridViewRowHeadersWidthSizeMode 列挙型の AutoSizeToDisplayedHeaders または AutoSizeToFirstHeader フィールドを使用します。
スケーラビリティを最大限に高めるには、自動サイズ設定をオフにして、プログラムによるサイズ変更を使用します。
詳細については、「Windows フォーム DataGridView コントロールのサイズ変更オプション」を参照してください。
選択したセル、行、列のコレクションの効率的な使用
SelectedCells コレクションは、大規模な選択では効率的に実行されません。 SelectedRows および SelectedColumns コレクションも非効率的ですが、その度合いは低くなります。一般的な DataGridView コントロールではセルよりも行がはるかに少なく、行よりも列がはるかに少ないためです。 これらのコレクションを使用する場合、パフォーマンスが低下しないようにするには、次のガイドラインに従ってください。
SelectedCells コレクションの内容にアクセスする前に、DataGridView 内のすべてのセルが選択されているかどうかを判断するために、AreAllCellsSelected メソッドの戻り値を確認します。 ただし、このメソッドを使用すると、行が非共有になる可能性があることに注意してください。 詳細については、次のセクションを参照してください。
選択されているセル数を確認するために System.Windows.Forms.DataGridViewSelectedCellCollection の Count プロパティを使用することは避けてください。 代わりに DataGridView.GetCellCount メソッドを使用し、DataGridViewElementStates.Selected の値を渡します。 同様に、選択された行と列のコレクションにアクセスするのではなく、DataGridViewRowCollection.GetRowCount および DataGridViewColumnCollection.GetColumnCount メソッドを使用して選択されている要素数を確認します。
セルベースの選択モードは避けてください。 代わりに DataGridView.SelectionMode プロパティを DataGridViewSelectionMode.FullRowSelect または DataGridViewSelectionMode.FullColumnSelect に設定します。
共有行の使用
DataGridView コントロールでは、共有行によって効率的なメモリ使用が実現されています。 行により、DataGridViewRow クラスのインスタンスを共有することで、外観と動作に関する情報をできるだけ多く共有します。
行インスタンスを共有するとメモリが節約されますが、行は簡単に非共有になる可能性があります。 たとえば、ユーザーがセルを直接操作すると、その行は非共有になります。 これは避けられないため、このトピックのガイドラインは、非常に大量のデータを操作する場合と、プログラムを実行するたびにユーザーがデータの比較的小さな部分を操作する場合にのみ役立ちます。
バインドされていない DataGridView コントロールでは、セルに値が含まれている場合、その行を共有することはできません。 DataGridView コントロールが外部データ ソースにバインドされている場合や、仮想モードを実装して独自のデータ ソースを提供する場合は、セルの値はセル オブジェクトではなくコントロールの外部に格納されるので、行を共有することができます。
行オブジェクトを共有できるのは、行の状態とセルを含む列の状態から、すべてのセルの状態を判断できる場合のみです。 セルの状態を変更して、行と列の状態から推測できなくなった場合、その行は共有できません。
たとえば、次のような場合は、行を共有することはできません。
行に、選択された列内にない、選択された 1 つのセルがある。
行に、ToolTipText または ContextMenuStrip のプロパティが設定されたセルがある。
行に、Items プロパティが設定された DataGridViewComboBoxCell が含まれている。
バインド モードや仮想モードでは、CellToolTipTextNeeded および CellContextMenuStripNeeded イベントを処理することで、個々のセルにヒントやショートカット メニューを提供することができます。
DataGridViewRowCollection に行が追加されるたびに、DataGridView コントロールにより、共有行の使用が自動的に試行されます。 行を確実に共有するには、次のガイドラインに従ってください。
Add メソッドの
Add(Object[])
オーバーロードと DataGridView.Rows コレクションの Insert メソッドのInsert(Object[])
オーバーロードの呼び出しは避けてください。 このようなオーバーロードにより、非共有行が自動的に作成されます。次のような場合は、DataGridView.RowTemplate プロパティで指定した行を共有できることを確認してください。
DataGridView.Rows コレクションの Add メソッドの
Add()
またはAdd(Int32)
オーバーロード、Insert メソッドのInsert(Int32,Int32)
オーバーロードを呼び出す場合。DataGridView.RowCount プロパティの値を増やす場合。
DataGridView.DataSource プロパティを設定する場合。
DataGridView.Rows コレクションの AddCopy、AddCopies、InsertCopy、InsertCopies メソッドを呼び出すときは、
indexSource
パラメーターで指定した行を共有できることを確認してください。Add メソッドの
Add(DataGridViewRow)
オーバーロード、AddRange メソッド、Insert メソッドのInsert(Int32,DataGridViewRow)
オーバーロード、DataGridView.Rows コレクションの InsertRange メソッドを呼び出すときは、指定した行を共有できることを確認してください。
行が共有されているかどうかを判断するには、DataGridViewRowCollection.SharedRow メソッドを使用して行オブジェクトを取得し、オブジェクトの Index プロパティを確認します。 共有行は、常に Index プロパティの値が -1 です。
行が非共有にならないようにする
コードやユーザーの操作によって、共有行が非共有になることがあります。 パフォーマンスへの影響を避けるためには、行が非共有にならないようにする必要があります。 アプリケーションの開発時に RowUnshared イベントを処理することで、行が非共有になったときを判別できるようになります。 これは、行共有の問題をデバッグするときに便利です。
行が非共有にならないようにするには、次のガイドラインに従ってください。
Rows コレクションにインデックスを付けることや、
foreach
ループを使用して反復処理することは避けてください。 通常、行に直接アクセスする必要はありません。 行を操作する DataGridView メソッドは、行インスタンスではなく行インデックスの引数を受け取ります。 さらに、行に関連するイベントのハンドラーは、行のプロパティを持つイベント引数オブジェクトを受け取るので、これを使用すれば、行を非共有にすることなく操作できます。行オブジェクトにアクセスする必要がある場合は、DataGridViewRowCollection.SharedRow メソッドを使用して、行の実際のインデックスを渡します。 ただし、このメソッドで取得した共有行オブジェクトを変更すると、そのオブジェクトを共有しているすべての行が変更されることに注意してください。 ただし、新規レコードの行は他の行と共有されないため、他の行を変更しても影響を受けません。 また、共有行で表される行によって、ショートカット メニューが異なる場合があることにも注意してください。 共有行インスタンスから正しいショートカット メニューを取得するには、GetContextMenuStrip メソッドを使用し、行の実際のインデックスを渡します。 代わりに共有行の ContextMenuStrip プロパティにアクセスすると、共有行のインデックス -1 が使用され、正しいショートカット メニューを取得できません。
DataGridViewRow.Cells コレクションにインデックスを付けることは避けてください。 セルに直接アクセスすると、その親行が非共有になり、新しい DataGridViewRow のインスタンスが作成されます。 セル関連のイベントのハンドラーは、セルのプロパティを持つイベント引数オブジェクトを受け取ります。このオブジェクトを使用すると、行が非共有になることなくセルを操作できます。 また、CurrentCellAddress プロパティを使用すると、セルに直接アクセスすることなく、現在のセルの行と列のインデックスを取得することができます。
セルベースの選択モードは避けてください。 これらのモードにより、行は非共有になります。 代わりに DataGridView.SelectionMode プロパティを DataGridViewSelectionMode.FullRowSelect または DataGridViewSelectionMode.FullColumnSelect に設定します。
DataGridViewRowCollection.CollectionChanged または DataGridView.RowStateChanged イベントを処理しないでください。 これらのイベントにより、行は非共有になります。 また、これらのイベントを発生させる DataGridViewRowCollection.OnCollectionChanged または DataGridView.OnRowStateChanged メソッドを呼び出さないでください。
DataGridView.SelectionMode プロパティの値が FullColumnSelect、ColumnHeaderSelect、FullRowSelect、RowHeaderSelect のときは、DataGridView.SelectedCells コレクションにアクセスしないでください。 これにより、選択されているすべての行が非共有になります。
DataGridView.AreAllCellsSelected メソッドは呼び出さないでください。 このメソッドを使用すると、行が非共有になる可能性があります。
DataGridView.SelectionMode プロパティ値が CellSelect の場合は、DataGridView.SelectAll メソッドを呼び出さないでください。 これにより、すべての行が非共有になります。
列の対応するプロパティが
true
に設定されている場合は、セルの ReadOnly または Selected プロパティをfalse
に設定しないでください。 これにより、すべての行が非共有になります。DataGridViewRowCollection.List プロパティにはアクセスしないでください。 これにより、すべての行が非共有になります。
Sort メソッドの
Sort(IComparer)
オーバーロードを呼び出さないでください。 カスタムの比較子を使用して並べ替えると、すべての行が非共有になります。