Windows フォーム DataGridView コントロールを拡張するための推奨される手順

DataGridView コントロールは、最大限のスケーラビリティを達成するように設計されています。 大量のデータを表示する必要がある場合は、このトピックで説明するガイドラインに従って、大量のメモリを消費したり、ユーザー インターフェイス (UI) の応答性が低下したりしないようにする必要があります。 このトピックでは、以下の問題について説明します。

  • セル スタイルの効率的な使用

  • ショートカット メニューの効率的な使用

  • 自動サイズ変更の効率的な使用

  • 選択したセル、行、列のコレクションの効率的な使用

  • 共有行の使用

  • 行が非共有にならないようにする

特別なパフォーマンスが必要な場合は、仮想モードを実装して、独自のデータ管理操作を行うことができます。 詳細については、「Windows フォーム DataGridView コントロールでのデータ表示モード」を参照してください。

セル スタイルの効率的な使用

各セル、行、列には、それぞれスタイル情報を持たせることができます。 スタイル情報は DataGridViewCellStyle オブジェクトに格納されます。 個々の多数の DataGridView 要素に対してセル スタイル オブジェクトを作成することは、特に大量のデータを扱う場合には非効率的である可能性があります。 パフォーマンスへの影響を避けるには、次のガイドラインに従ってください。

ショートカット メニューの効率的な使用

各セル、行、列にはそれぞれショートカット メニューを設定できます。 DataGridView コントロールのショートカット メニューは ContextMenuStrip コントロールで表されます。 セル スタイル オブジェクトと同様に、個々の DataGridView 要素に多数のショートカット メニューを作成すると、パフォーマンスに悪影響を及ぼします。 このペナルティを回避するには、次のガイドラインに従ってください。

  • 個々のセルと行に対してショートカット メニューを作成することは避けてください。 これには、コントロールに新しい行が追加されたときにショートカット メニューと共に複製される行テンプレートも含まれます。 スケーラビリティを最大限に高めるには、コントロールの ContextMenuStrip プロパティのみを使用して、コントロール全体に 1 つのショートカット メニューを指定します。

  • 複数の行やセルに対して複数のショートカット メニューが必要な場合は、CellContextMenuStripNeeded または RowContextMenuStripNeeded イベントを処理します。 これらのイベントを使用すると、ショートカット メニューのオブジェクトを自分で管理して、パフォーマンスを調整することができます。

自動サイズ変更の効率的な使用

行、列、ヘッダーは、セルの内容が変化すると自動的にサイズが変更され、セルの内容全体がクリッピングされることなく表示されます。 サイズ設定モードを変更して、行、列、およびヘッダーのサイズを変更することもできます。 正しいサイズを決定するために、DataGridView コントロールを使用して、収容しなければならない各セルの値を調べる必要があります。 大規模なデータセットを扱う場合、自動サイズ変更が発生すると、この分析がコントロールのパフォーマンスに悪影響を与える可能性があります。 パフォーマンスが低下しないようにするには、次のガイドラインに従ってください。

詳細については、「Windows フォーム DataGridView コントロールのサイズ変更オプション」を参照してください。

選択したセル、行、列のコレクションの効率的な使用

SelectedCells コレクションは、大規模な選択では効率的に実行されません。 SelectedRows および SelectedColumns コレクションも非効率的ですが、その度合いは低くなります。一般的な DataGridView コントロールではセルよりも行がはるかに少なく、行よりも列がはるかに少ないためです。 これらのコレクションを使用する場合、パフォーマンスが低下しないようにするには、次のガイドラインに従ってください。

共有行の使用

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 コレクションの AddCopyAddCopiesInsertCopyInsertCopies メソッドを呼び出すときは、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 プロパティの値が FullColumnSelectColumnHeaderSelectFullRowSelectRowHeaderSelect のときは、DataGridView.SelectedCells コレクションにアクセスしないでください。 これにより、選択されているすべての行が非共有になります。

  • DataGridView.AreAllCellsSelected メソッドは呼び出さないでください。 このメソッドを使用すると、行が非共有になる可能性があります。

  • DataGridView.SelectionMode プロパティ値が CellSelect の場合は、DataGridView.SelectAll メソッドを呼び出さないでください。 これにより、すべての行が非共有になります。

  • 列の対応するプロパティが true に設定されている場合は、セルの ReadOnly または Selected プロパティを false に設定しないでください。 これにより、すべての行が非共有になります。

  • DataGridViewRowCollection.List プロパティにはアクセスしないでください。 これにより、すべての行が非共有になります。

  • Sort メソッドの Sort(IComparer) オーバーロードを呼び出さないでください。 カスタムの比較子を使用して並べ替えると、すべての行が非共有になります。

関連項目