縮放 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 屬性。 如果尚未使用 屬性, DataGridViewCellStyle 則 Style 存取 屬性會建立 類別的新實例。 此外,如果某些樣式繼承自資料列、資料行或控制項,此物件可能不會包含儲存格的完整樣式資訊。 如需儲存格樣式繼承的詳細資訊,請參閱 Windows Forms DataGridView 控制項 中的儲存格樣式。
有效率地使用快顯功能表
每個儲存格、資料列和資料行都可以有自己的快捷方式功能表。 控制項中的 DataGridView 快顯功能表是由 ContextMenuStrip 控制項表示。 就像儲存格樣式物件一樣,為許多個別 DataGridView 元素建立快顯功能表會對效能造成負面影響。 若要避免此懲罰,請使用下列指導方針:
避免為個別儲存格和資料列建立快顯功能表。 這包括資料列範本,當新的資料列新增至 控制項時,會連同其快捷方式功能表一起複製。 若要達到最大延展性,請只使用控制項的 ContextMenuStrip 屬性來指定整個控制項的單一快捷方式功能表。
如果您需要多個資料列或儲存格的多個快顯功能表,請處理 CellContextMenuStripNeeded 或 RowContextMenuStripNeeded 事件。 這些事件可讓您自行管理快捷方式功能表物件,讓您微調效能。
有效率地使用自動調整大小
資料列、資料行和標頭可以隨著儲存格內容變更而自動調整大小,讓儲存格的整個內容顯示而不裁剪。 變更調整大小模式也可以調整資料列、資料行和標頭的大小。 若要判斷正確的大小, DataGridView 控制項必須檢查它必須容納的每個儲存格值。 使用大型資料集時,此分析可能會對自動調整大小時控制項的效能產生負面影響。 若要避免效能降低,請使用下列指導方針:
避免在具有一組大型資料列的 DataGridView 控制項上使用自動調整大小。 如果您使用自動調整大小,則只會根據顯示的資料列調整大小。 也只使用虛擬模式中顯示的資料列。
針對資料列和資料行,請使用
DisplayedCells
、 DataGridViewAutoSizeColumnsMode 和 DataGridViewAutoSizeColumnMode 列舉的 DataGridViewAutoSizeRowsMode 或DisplayedCellsExceptHeaders
欄位。針對資料列標頭,請使用 AutoSizeToDisplayedHeaders 列舉的 DataGridViewRowHeadersWidthSizeMode 或 AutoSizeToFirstHeader 欄位。
若要達到最大延展性,請關閉自動調整大小,並使用程式設計調整大小。
如需詳細資訊,請參閱 Windows Forms DataGridView 控制項 中的調整大小選項。
有效率地使用選取的儲存格、資料列和資料行集合
集合 SelectedCells 不會透過大型選取專案有效率地執行。 SelectedRows和 SelectedColumns 集合也可能效率低下,不過,雖然在較小的程度下,因為資料列比一般 DataGridView 控制項中的資料格少很多,而且資料行比資料列少很多。 若要避免使用這些集合時的效能降低,請使用下列指導方針:
若要判斷 在 DataGridView 存取集合的內容 SelectedCells 之前,是否已選取 中的所有儲存格,請檢查 方法的 AreAllCellsSelected 傳回值。 不過請注意,此方法可能會導致資料列取消共用。 如需詳細資訊,請參閱一節。
請避免使用 Count 的 System.Windows.Forms.DataGridViewSelectedCellCollection 屬性來判斷選取的儲存格數目。 請改用 DataGridView.GetCellCount 方法並傳入 DataGridViewElementStates.Selected 值。 同樣地,使用 DataGridViewRowCollection.GetRowCount 和 DataGridViewColumnCollection.GetColumnCount 方法來判斷選取的專案數目,而不是存取選取的資料列和資料行集合。
避免以儲存格為基礎的選取模式。 相反地,將 DataGridView.SelectionMode 屬性設定為 DataGridViewSelectionMode.FullRowSelect 或 DataGridViewSelectionMode.FullColumnSelect 。
使用共用資料列
透過共用資料列在 DataGridView 控制項中實現有效率的記憶體使用。 資料列會藉由共用 類別的 DataGridViewRow 實例,盡可能共用其外觀和行為的相關資訊。
共用資料列實例可節省記憶體時,資料列可以輕鬆地取消共用。 例如,每當使用者直接與儲存格互動時,其資料列就會變成未共用。 由於無法避免,本主題中的指導方針只有在使用非常大量的資料時才有用,而且只有在每次執行程式時,使用者才會與相對較小的資料互動時使用。
如果其中任何儲存格包含值,就無法在未系結 DataGridView 的控制項中共用資料列。 DataGridView當控制項系結至外部資料源或實作虛擬模式並提供自己的資料來源時,資料格值會儲存在控制項外部,而不是儲存在儲存格物件中,讓資料列可供共用。
只有當所有資料格的狀態都可以從資料列的狀態和包含儲存格的資料行狀態判斷時,才能共用資料列物件。 如果您變更儲存格的狀態,使其無法再從其資料列和資料行的狀態推斷出來,則無法共用資料列。
例如,在下列任何情況下,都無法共用資料列:
資料列包含不在選取資料行中的單一選取儲存格。
資料列包含具有其 ToolTipText 或 ContextMenuStrip 屬性集的儲存格。
資料列包含 DataGridViewComboBoxCell 其 Items 屬性集的 。
在系結模式或虛擬模式中,您可以藉由處理 CellToolTipTextNeeded 和 CellContextMenuStripNeeded 事件,提供個別儲存格的工具提示和快顯功能表。
DataGridView每當資料列加入 至 DataGridViewRowCollection 時,控制項就會自動嘗試使用共用資料列。 使用下列指導方針確保共用資料列:
請避免呼叫
Add(Object[])
方法的多 Add 載和Insert(Object[])
集合方法的多 DataGridView.Rows 載 Insert 。 這些多載會自動建立未共用的資料列。請確定屬性中指定的 DataGridView.RowTemplate 資料列可以在下列案例中共用:
呼叫
Add()
方法的 Add 或 多載時Add(Int32)
,或Insert(Int32,Int32)
集合之 方法的多載。 InsertDataGridView.Rows增加 屬性的值 DataGridView.RowCount 時。
設定 DataGridView.DataSource 屬性時。
請確定呼叫 集合的 、 、 和 方法時,可以共用 參數所指示
indexSource
的資料 DataGridView.Rows 列。 InsertCopiesInsertCopyAddCopiesAddCopy請確定呼叫 方法的多載、方法、
Insert(Int32,DataGridViewRow)
AddRange 方法的多載 InsertAdd 和 InsertRange 集合的 方法 DataGridView.Rows 方法時,可以共用Add(DataGridViewRow)
指定的資料列或資料列。
若要判斷資料列是否共用,請使用 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 方法。
當屬性值為 FullColumnSelect 、、 ColumnHeaderSelectFullRowSelect 或 RowHeaderSelect 時 DataGridView.SelectionMode ,請勿存取 DataGridView.SelectedCells 集合。 這會導致所有選取的資料列變成未共用。
請勿呼叫 DataGridView.AreAllCellsSelected 方法。 此方法可能會導致資料列取消共用。
當屬性值為 CellSelect 時 DataGridView.SelectionMode ,請勿呼叫 DataGridView.SelectAll 方法。 這會導致所有資料列都取消共用。
當資料行中的對應屬性設定為 時,請勿 ReadOnly 將儲存格
false
的 或 Selected 屬性設定為true
。 這會導致所有資料列都取消共用。請勿存取 DataGridViewRowCollection.List 屬性。 這會導致所有資料列都取消共用。
請勿呼叫
Sort(IComparer)
方法的多 Sort 載。 使用自訂比較子排序會導致所有資料列都取消共用。
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應