縮放 Windows Form DataGridView 控制項的最佳作法
DataGridView 控制項的設計目的是提供最大的延展性。 如果您需要顯示大量資料,您應該遵循本主題中所述的指導方針,以避免耗用大量的記憶體或降低使用者介面 (UI) 的回應性。 這個主題將討論下列問題:
有效率地使用儲存格樣式
有效率地使用捷徑功能表
有效率地使用自動重設大小
有效率地使用選取的儲存格、資料列及資料行集合
使用共用資料列
防止資料列未共用
如果您有特殊的效能需求,您可以實作虛擬模式並提供您自己的資料管理作業。 如需詳細資訊,請參閱 Windows Forms DataGridView 控制項中的資料顯示模式。
有效率地使用儲存格樣式
每個儲存格、資料列及資料行都可以有自己的樣式資訊。 樣式資訊會儲存在 DataGridViewCellStyle 物件中。 為許多個別 DataGridView 元素建立儲存格樣式物件可能會沒有效率,尤其是在處理大量資料時。 若要避免效能影響,請使用下列指導方針:
避免為個別 DataGridViewCell 或 DataGridViewRow 物件設定儲存格樣式屬性。 這包括由 RowTemplate 屬性指定的資料列物件。 從資料列範本複製的每個新資料列,將會收到範本儲存格樣式物件自己的複本。 若要達到最大延展性,請在 DataGridView 層級設定儲存格樣式屬性。 例如,設定 DataGridView.DefaultCellStyle 屬性,而不是 DataGridViewCell.Style 屬性。
如果某些儲存格需要格式化預設格式以外的格式,請在儲存格、資料列或資料行群組之間使用相同的 DataGridViewCellStyle 執行個體。 避免直接在個別儲存格、資料列及資料行上設定類型 DataGridViewCellStyle 的屬性。 如需儲存格樣式共用的範例,請參閱如何:設定 Windows Forms DataGridView 控制項的預設儲存格樣式。 您也可以藉由處理 CellFormatting 事件處理程式,個別設定儲存格樣式時避免效能降低。 如需範例,請參閱操作說明:自訂 Windows Forms DataGridView 控制項中的資料格式。
判斷儲存格的樣式時,請使用 DataGridViewCell.InheritedStyle 屬性,而不是 DataGridViewCell.Style 屬性。 如果尚未使用屬性,則存取 Style 屬性會建立 DataGridViewCellStyle 類別的新執行個體。 此外,如果某些樣式繼承自資料列、資料行或控制項,此物件可能不會包含儲存格的完整樣式資訊。 如需關於儲存格樣式繼承的詳細資訊,請參閱 Windows Forms DataGridView 控制項中的儲存格樣式。
有效率地使用捷徑功能表
每個儲存格、資料列及資料行都可以有自己的捷徑功能表。 DataGridView 控制項中的捷徑功能表是由 ContextMenuStrip 控制項表示。 就像儲存格樣式物件一樣,為許多個別的 DataGridView 元素建立捷徑功能表將會對效能造成負面影響。 若要避免此處罰,請使用下列指導方針:
避免為個別儲存格和資料列建立捷徑功能表。 這包括資料列範本,當新的資料列新增至控制項時,會連同其捷徑功能表一起複製。 若要達到最大延展性,請只使用控制項的 ContextMenuStrip 屬性來指定整個控制項的單一捷徑功能表。
如果您需要多個資料列或儲存格的多個捷徑功能表,請處理 CellContextMenuStripNeeded 或 RowContextMenuStripNeeded 事件。 這些事件可讓您自行管理捷徑功能表物件,讓您微調效能。
有效率地使用自動重設大小
資料列、資料行及標頭可以隨著儲存格內容變更而自動重設大小,讓儲存格的整個內容顯示而不裁剪。 變更重設大小模式也可以調整資料列、資料行及標頭的大小。 若要判斷正確的大小,DataGridView 控制項必須檢查它必須容納的每個儲存格值。 使用大型資料集時,此分析可能會對自動重設大小時控制項的效能產生負面影響。 若要避免效能降低,請使用下列指導方針:
請避免在具有大量資料列的 DataGridView 控制項上使用自動重設大小。 如果您使用自動重設大小,則只會依據顯示的資料列重設大小。 也只使用虛擬模式中顯示的資料列。
針對資料列和資料行,請使用 DataGridViewAutoSizeRowsMode、DataGridViewAutoSizeColumnsMode 及 DataGridViewAutoSizeColumnMode 列舉的
DisplayedCells
或DisplayedCellsExceptHeaders
欄位。針對資料列標頭,請使用 DataGridViewRowHeadersWidthSizeMode 列舉的 AutoSizeToDisplayedHeaders 或 AutoSizeToFirstHeader 欄位。
若要達到最大延展性,請關閉自動重設大小,並使用程式設計重設大小。
如需詳細資訊,請參閱 Windows Forms 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 控制項繫結至外部資料來源或實作虛擬模式並提供自己的資料來源時,儲存格值會儲存在控制項外部,而不是儲存在儲存格物件中,讓資料列可供共用。
只有當所有儲存格的狀態都可以從資料列的狀態和包含儲存格的資料行狀態判斷時,才能共用資料列物件。 如果您變更儲存格的狀態,使其無法再從其資料列和資料行的狀態推斷出來,則無法共用資料列。
例如,在下列任何情況都無法共用資料列:
資料列包含不在選取資料行中單一選取的儲存格。
資料列包含具有其 ToolTipText 或 ContextMenuStrip 屬性集的儲存格。
資料列包含具有其 Items 屬性集的 DataGridViewComboBoxCell。
在繫結模式或虛擬模式中,您可以藉由處理 CellToolTipTextNeeded 和 CellContextMenuStripNeeded 事件,為個別儲存格提供工具提示和捷徑功能表。
每當將資料列加入至 DataGridViewRowCollection 時,DataGridView 控制項會自動嘗試使用共用資料列。 使用下列指導方針確保共用資料列:
請避免呼叫 Add 方法的
Add(Object[])
多載,以及 DataGridView.Rows 集合 Insert 方法的Insert(Object[])
多載。 這些多載會自動建立未共用的資料列。請確定 DataGridView.RowTemplate 屬性中指定的資料列可以在下列情況下共用:
呼叫 Add 方法的
Add()
或Add(Int32)
多載或 DataGridView.Rows 集合 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 屬性。 共用資料列一律具有 –1 的 Index 屬性值。
防止資料列成為未共用
共用的資料列可能會因為程式碼或使用者動作而取消共用。 若要避免影響效能,您應該避免造成資料列取消共用。 在應用程式開發期間,您可以處理 RowUnshared 事件,以判斷資料列何時取消共用。 偵錯資料列共用問題時,這非常有用。
若要防止資料列未共用,請使用下列指導方針:
請避免使用
foreach
迴圈編製 Rows 集合的索引或逐一查看。 您通常不需要直接存取資料列。 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)
多載。 使用自訂比較子排序會導致所有資料列都取消共用。