DataGridView控件 ios
DataGridView是用於Windows Froms 2.0的新網格控件。它能夠取代先前版本中DataGrid控件,它易於使用並高度可定製,支持不少咱們的用戶須要的特性。 數據庫
關於本文檔: 編程
本文檔不許備面面俱到地介紹DataGridView,而是着眼於深刻地介紹一些技術點的高級特性。 數組
本文檔按邏輯分爲5個章節,首先是結構和特性的概覽,其次是內置的列/單元格類型的介紹,再次是數據操做相關的內容,而後是主要特性的綜述,最後是最佳實踐。 緩存
大部分章節含有一個「Q & A」部分,來回答該章節相關的一些常見問題。注意,某些問題會因爲知識點的關聯性重複出如今多個章節。這些問題、答案及其附帶的示例代碼都包含在本文檔的附錄部分。 網絡
內容 app
1 何爲DataGridView.. 4 less
1.1 DataGridView和DataGrid 之間的區別... 4 ide
1.2 DataGridView的亮點... 5 函數
2 DataGridView的結構... 6
2.1 結構元素... 6
2.2 單元格和組... 6
2.3 DataGridView的單元格... 6
2.3.1 DataGridViewCell的工做機制... 7
2.4 DataGridView的列... 9
2.5 DataGridView的編輯控件... 9
2.6 DataGridView的行... 10
3 列/單元格類型揭密... 11
3.1 DataGridViewTextBoxColumn. 11
3.2 DataGridViewCheckBoxColumn. 12
3.3 DataGridViewImageColumn. 12
3.4 DataGridViewButtonColumn. 13
3.5 DataGridViewComboBoxColumn. 13
3.5.1 DataError與ComboBox列... 13
3.6 DataGridViewLinkColumn. 14
4 操做數據... 15
4.1 數據輸入和驗證的相關事件... 15
4.1.1 數據驗證相關事件的順序... 15
4.1.2 驗證數據... 15
4.1.3 在新行中的數據輸入... 16
4.2 關於Null值... 19
4.2.1 NullValue屬性... 19
4.2.2 DataSourceNullValue屬性... 19
4.3 DataError事件... 20
4.4 數據綁定模式... 21
4.4.1 非綁定模式... 21
4.4.2 綁定模式... 21
4.4.3 虛擬模式... 22
4.4.4 混合模式... 22
5 Overview of features. 24
5.1 Styling. 24
5.1.1 The DataGridViewCellStyle Class. 24
5.1.2 Using DataGridViewCellStyle Objects. 24
5.1.3 Style Inheritance. 25
5.1.4 Setting Styles Dynamically. 28
5.2 Custom painting. 28
5.2.1 Paint Parts. 28
5.2.2 Row Pre Paint and Post Paint 29
5.3 Autosizing. 30
5.3.1 Sizing Options in the Windows Forms DataGridView Control 30
5.3.2 Resizing with the Mouse. 31
5.3.3 Automatic Sizing. 32
5.3.4 Programmatic Resizing. 33
5.3.5 Customizing Content-based Sizing Behavior. 34
5.3.6 Content-based Sizing Options. 34
5.4 Selection modes. 34
5.4.1 Programmatic Selection. 35
5.5 Scrolling. 35
5.5.1 Scroll event 35
5.5.2 Scroll bars. 35
5.5.3 Scrolling Properties. 36
5.6 Sorting. 36
5.6.1 Programmatic Sorting. 37
5.6.2 Custom Sorting. 38
5.7 Border styles. 39
5.7.1 Standard Border Styles. 39
5.7.2 Advanced Border Styles. 39
5.8 Enter-Edit modes. 40
5.9 Clipboard copy modes. 40
5.10 Frozen columns/rows. 41
5.11 Implementing Custom cells and editing controls/cells. 41
5.11.1 IDataGridViewEditingControl 42
5.11.2 IDataGridViewEditingCell 42
5.12 Virtual mode. 42
5.12.1 Bound Mode and Virtual Mode. 42
5.12.2 Supplementing Bound Mode. 42
5.12.3 Replacing Bound Mode. 43
5.12.4 Virtual-Mode Events. 43
5.12.5 Best Practices in Virtual Mode. 44
5.13 Capacity. 44
6 Best Practices. 45
6.1 Using Cell Styles Efficiently. 45
6.2 Using Shortcut Menus Efficiently. 45
6.3 Using Automatic Resizing Efficiently. 45
6.4 Using the Selected Cells, Rows, and Columns Collections Efficiently. 46
6.5 Using Shared Rows. 46
6.6 Preventing Rows from Becoming Unshared. 47
附錄 A – 常見問題:... 49
1. 如何使指定的單元格不可編輯?. 49
2. 如何讓一個單元格不可用?. 49
3. 如何避免用戶將焦點設置到指定的單元格?... 51
4. 如何使全部單元格老是顯示控件(不論它是否處於編輯狀態)?. 51
5. Why does the cell text show up with 「square」 characters where they should be new lines?. 51
6. 如何在單元格內同時顯示圖標和文本?... 51
7. 如何隱藏一列?... 53
8. 如何避免用戶對列排序?... 53
9. 如何針對多個列排序?. 54
10. 如何爲編輯控件添加事件處理函數?. 58
11. 應在什麼時候移除編輯控件的事件處理函數?. 58
12. 如何處理ComboBox列中ComboBox控件的SelectIndexChanged事件?. 58
13. 如何經過拖放調整行的順序?... 59
14. 如何調整最後一列的寬度使其佔據網格的剩餘客戶區?... 60
15. 如何讓TextBox類型的單元格支持換行?. 60
16. 如何使Image列不顯示任何圖像(字段值爲null時)?. 61
17. 如何可以在ComboBox類型的單元格中輸入數據?. 61
18. How do I have a combo box column display a sub set of data based upon the value of a different combo box column? 61
19. 如何在用戶編輯控件的時候(而不是在驗證時)就顯示錯誤圖標?. 62
20. 如何同時顯示綁定數據和非綁定數據?... 65
21. How do I show data that comes from two tables?. 66
22. 如何顯示主從表?... 66
23. 如何在同一DataGridView中顯示主從表?... 68
24. 如何避免用戶對列排序?. 68
25. 如何在點擊工具欄按鈕的時候將數據提交到數據庫?... 68
26. 如何在用戶刪除記錄時顯示確認對話框?... 68
經過DataGridView控件,能夠顯示和編輯表格式的數據,而這些數據能夠取自多種不一樣類型的數據源。
DataGridView控件具備很高的的可配置性和可擴展性,提供了大量的屬性、方法和事件,能夠用來對該控件的外觀和行爲進行自定義。當你須要在WinForm應用程序中顯示錶格式數據時,能夠優先考慮DataGridView(相比於DataGrid等其它控件)。若是你要在小型網格中顯示只讀數據,或者容許用戶編輯數以百萬計的記錄,DataGridView將爲你提供一個易於編程和良好性能的解決方案。
DataGridView 用來替換先前版本中的DataGrid,擁有較DataGrid更多的功能;但DataGrid仍然獲得保留,以備向後兼容和未來使用。若是你要在二者中選擇,能夠參考下面給出的DataGrid 和DataGridView之間區別的細節信息。
DataGridView提供了大量的DataGrid所不具有的基本功能和高級功能。此外,DataGridView 的結構使得它較之DataGrid控件更容易擴展和自定義。
下表描述了DataGridView提供而DataGrid未提供的幾個主要功能。
DataGridView功能 |
描述 |
多種列類型 |
與DataGrid相比,DataGridView 提供了更多的內置列類型。這些列類型可以知足大部分常見須要,並且比DataGrid中的列類型易於擴展或替換。 |
多種數據顯示方式 |
DataGrid僅限於顯示外部數據源的數據。而DataGridView則可以顯示非綁定的數據,綁定的數據源,或者同時顯示綁定和非綁定的數據。你也能夠在DataGridView中實現virtual mode,實現自定義的數據管理。 |
用於自定義數據顯示的多種方式 |
DataGridView提供了不少屬性和事件,用於數據的格式化和顯示。好比,你能夠根據單元格、行和列的內容改變其外觀,或者使用一種類型的數據替代另外一種類型的數據。 |
用於更改單元格、行、列、表頭外觀和行爲的多個選項 |
DataGridView使你可以以多種方式操做單個網格組件。好比,你能夠凍結行和列,避免它們因滾動而不可見;隱藏行、列、表頭;改變行、列、表頭尺寸的調整方式;爲單個的單元格、行和列提供工具提示(ToolTip)和快捷菜單。 |
惟一的一個DataGrid提供而DataGridView未提供的特性是兩個相關表中數據的分層次顯示(好比常見的主從表顯示)。你必須使用兩個DataGridView來顯示具備主從關係的兩個表的數據。
下表着重顯示了DataGridView的主要特性,稍後會介紹它們的詳細信息。
DataGridView控件特性 |
描述 |
多種列類型 |
DataGridView提供有TextBox、CheckBox、Image、Button、ComboBox和Link類型的列及相應的單元格類型。 |
多種數據顯示方式 |
DataGrid僅限於顯示外部數據源的數據。而DataGridView則可以顯示非綁定的數據,綁定的數據源,或者同時顯示綁定和非綁定的數據。你也能夠在DataGridView中實現virtual mode,實現自定義的數據管理。 |
自定義數據的顯示和操做的多種方式 |
DataGridView提供了不少屬性和事件,用於數據的格式化和顯示。 此外,DataGridView提供了操做數據的多種方式,好比,你能夠:
|
用於更改單元格、行、列、表頭外觀和行爲的多個選項 |
DataGridView使你可以以多種方式操做單個網格組件。好比,你能夠:
|
提供豐富的可擴展性的支持 |
DataGridView提供易於對網格進行擴展和自定義的基礎結構,好比:
|
DataGridView及其相關類被設計爲用於顯示和編輯表格數據式數據的靈活的、可擴展的體系。這些類都位於system.Windows.Forms命名空間,它們的名稱也都有共同的前綴"DataGridView"。
主要的DataGridView相關類繼承自DataGridViewElement類。
DataGridViewElement類有兩個屬性,一是DataGridView,該屬性提供了對其所屬的DataGridView的引用;二是State,該屬性表示當前的狀態,其值爲DataGridViewElementStates枚舉,該枚舉支持位運算,這意味着能夠設置組合狀態。
DataGridView由兩種基本的對象組成:單元格(cell)和組(band)。全部的單元格都繼承自DataGridViewCell基類。 兩種類型的組(或稱集合)DataGridViewColumn和DataGridViewRow都繼承自DataGridViewBand 基類,表示一組結合在一塊兒的單元格。
DataGridView會與一些類進行互操做,但最常打交道的則是以下三個:DataGridViewCell, DataGridViewColumn,DataGridViewRow。
單元格(cell)是操做DataGridView的基本單位。Display is centered on cells, and data entry is often performed through cells。能夠經過DataGridViewRow 類的Cells 集合屬性訪問一行包含的單元格,經過DataGridView的SelectedCells集合屬性訪問當前選中的單元格,經過DataGridView的CurrentCell屬性訪問當前的單元格。
DataGridViewCell 類圖 |
Cell 相關類和屬性 |
DataGridViewCell是一個抽象基類,全部的單元格類型都繼承於此。DataGridViewCell及其繼承類型並非Windows Forms控件,但其中一些宿主於Windows Forms控件。單元格支持的編輯功能一般都由其宿主控件來處理。
DataGridViewCell對象不會像Windows Forms控件那樣控制本身的外觀和繪製(painting)特徵,相反的,DataGridView會負責其包含的單元格的外觀。經過DataGridView 控件的屬性和事件,你能夠深入地影響單元格的外觀和行爲。若是你對單元格定製有特殊要求,超出了DataGridView提供的功能,能夠繼承DataGridViewCell或者它的某個子類來知足這些要求。
理解DataGridView結構的一個重要部分是理解DataGridViewCell的工做機制:
單元格的值(A Cell’s Value)
單元格的值是其根本所在。若是單元格所在列不是綁定列,而且所在的DataGridView也不是Virtual Mode,那麼它的值就由它自己所持有並維護。對於那些由綁定產生的單元格,它們壓根兒就不「知道」該持有什麼值,固然也就不會去維護了;當DataGridView須要單元格的值的時候,它會到數據源中查詢該單元格應當顯示的值。在Virtual Mode下,除了會觸發CellValueNeeded事件以獲取相應單元格的值外,與數據綁定方式很是類似。在單元格級,全部這些由DataGridViewCell.GetValue() 方法來控制。
默認狀況下,單元格的值的類型爲object。當一個列被綁定後,會設置它的ValueType屬性,它包含的單元格的ValueType也隨之更新。而單元格的ValueType對於下一步的格式化很是重要。
格式化顯示(Formatting for Display)
注意:當DataGridView須要瞭解「如何顯示這個單元格」時,它須要的是單元格的FormattedValue ,而不是Value。這是一個複雜的過程,由於格式化屏幕上的一些內容一般須要將它轉換爲字符串。例如,儘管你將單元格的值(Value)設置爲整型值155,在顯示它的時候仍須要將其格式化。單元格和其所在的列的FormattedValueType 屬性決定了顯示它時所用的類型。多數列使用字符串類型,而Image和CheckBox類型的單元格/列則使用其它類型。Image類型的單元格和列使用Image做爲默認的FormattedValueType,它的內置實現瞭解如何去顯示一個Image。CheckBox類型的單元格/列的FormattedValueType屬性則取決於屬性ThreeState的值。在單元格級,全部這些由DataGridViewCell.GetFormattedValue()控制。
默認狀況下,DataGridView使用TypeConverter將單元格的值(Value)轉換爲格式化的值(FormattedValue)。DataGridView會基於單元格的ValueType和FormattedValueType屬性來獲取合時的TypeConverter。
對於一個單元格,FormattedValue會獲得屢次請求(即會在多個地方用到):繪製單元格的時候,所在列根據單元格內容自動調整大小的時候,甚至是在判斷鼠標是否通過單元格內容時。每次須要FormattedValue的時候,DataGridView會觸發CellFormatting事件,這時你就有機會修改單元格的格式化顯示了。
若是單元格不能獲取它的格式化值,它會觸發DataError事件。
格式化顯示單元格還包含以怎樣的首選尺寸顯示它。這個首選尺寸是由單元格的FormattedValue,填充區域(padding),附加顯示和邊框合併而成。
繪製單元格的顯示(Painting the Display)
在得到FormattedValue 後,單元格將負責繪製它的內容。單元格決定了繪製過程所使用的正確樣式(參見本文檔第五章的樣式部分)並進行繪製。記住:若是單元格不去繪製本身,那麼該單元格將不會有任何內容獲得繪製(即單元格的繪製只由它本身負責),行、列不會負責繪製任何內容,所以要確保至少要繪製單元格的背景(background),不然單元格所在的矩形區域仍然是無效的(即未經繪製)。
解析單元格的顯示(Parsing the Display)
用戶開始與單元格交互後,可能會編輯單元格的值。有一件事要記住,用戶編輯的其實是單元格的FormattedValue。用戶提交所編輯的值時,FormattedValue須要轉換回單元格的值(Value),這個過程稱爲解析(parsing)。在單元格級上,全部這些工做由單元格的DataGridViewCell.ParseFormattedValue(int rowIndex)方法控制。
默認狀況下,會再次使用TypeConverter來將FormattedValue解析爲單元格的真實值,這時會觸發DataGridView的CellParsing事件,這時你就有機會修改單元格的解析方式了。.
若是單元格不能獲得正確地解析,會觸發DataError事件。
4) 如何使全部單元格老是顯示控件(不論它們是否處於編輯狀態)?
5) Why does the cell text show up with 「square」 characters where they should be new lines?
DataGridView所附帶的數據(這些數據能夠經過綁定或非綁定方式附加到控件)的結構表現爲DataGridView的列。你可使用DataGridView的Columns集合屬性訪問DataGridView所包含的列,使用SelectedColumns 集合屬性訪問當前選中的列。
DataGridViewColumn 類圖 |
Column 相關類和屬性 |
一些主要的單元格類型擁有相應的列類型,這些列類型繼承自DataGridViewColumn基類。
常見問題:
1) 如何隱藏一列?
2) 如何避免用戶對列排序?
3) 如何針對多個列排序?
支持高級編輯功能的單元格通常都使用一個繼承自Windows Forms控件的宿主控件,這些控件同時也實現了IDataGridViewEditingControl接口。
DataGridView Editing Control Class diagram |
Classes that implement Editing Controls |
下表說明了單元格類型、列類型、編輯控件間的關係:
單元格類型 |
宿主控件 |
列類型 |
DataGridViewButtonCell |
n/a |
DataGridViewButtonColumn |
DataGridViewCheckBoxCell |
n/a |
DataGridViewCheckBoxColumn |
DataGridViewComboBoxCell |
DataGridViewComboBoxEditingControl |
DataGridViewComboBoxColumn |
DataGridViewImageCell |
n/a |
DataGridViewImageColumn |
DataGridViewLinkCell |
n/a |
DataGridViewLinkColumn |
DataGridViewTextBoxCell |
DataGridViewTextBoxEditingControl |
DataGridViewTextBoxColumn |
常見問題(FAQ)
3) 如何處理ComboBox列中Combox控件的SelectIndexChanged事件?
4) 如何使全部單元格老是顯示控件(不論它是否處於編輯狀態)?
DataGridViewRow類用於顯示數據源的一行數據。能夠經過DataGridView控件的Rows集合屬性來訪問其包含的行,經過SelectedRows集合屬性訪問當前選中的行。
DataGridViewRow類圖 |
Row相關的類和屬性 |
你能夠繼承DataGridViewRow類來實現本身的行類型,雖然多數狀況下這並沒必要要。DataGridView 有幾個行相關的事件和屬性,用以自定義其包含的DataGridViewRow對象的行爲。
若是你將DataGridView的AllowUserToAddRows屬性設爲true,一個專用於添加新行的特殊行會出如今最後一行的位置上,這一行也屬於Rows集合,但它有一些須要你提起注意的特殊功能,要得到這方面的更多信息,請參看4.1.3節。
DataGridView控件提供了幾種列類型用以顯示數據,並容許用戶修改和添加數據。
當你對DataGridView進行了綁定,並將它的AutoGenerateColumns屬性設置爲true,它會根據數據源中列的數據類型自動生成列,這些列都使用相應的默認類型(與數據源列數據類型相適應)。
你也能夠自行建立列的實例,將它們加入DataGridView的Columns集合中,這些列可用做非綁定列,也能夠以手動方式讓它們用於綁定數據。手動綁定的列很是有用,好比,自動生成的列都採用與數據源的列相應的默認類型,而你不想用默認列類型。
下表描述了DataGridView 的各類列對應的類:
列類型 |
描述 |
DataGridViewTextBoxColumn |
用於基於文本的值。綁定到數字和字符串值時會自動生成這種類型的列。 |
DataGridViewCheckBoxColumn |
用於顯示Boolean和CheckState類型的值,綁定到上述類型值時會自動生成這種類型的列。 |
DataGridViewImageColumn |
用於顯示圖像。綁定到byte數組,Image對象,圖標對象時會自動生成這種類型的列。 |
DataGridViewButtonColumn |
用於在單元格內顯示按鈕。在綁定時不會自動生成,通常用於非綁定列。 |
DataGridViewComboBoxColumn |
用於在單元格內顯示下拉列表。在綁定時不會自動生成,通常地須要手工綁定。 |
DataGridViewLinkColumn |
用於在單元格內顯示連接。在綁定時不會自動生成,通常地須要手工綁定。 |
自定義列類型 |
經過繼承DataGridViewColumn 類或其子類,你能夠建立本身的列類型,以提供自定義的外觀、行爲和宿主控件。 |
常見問題(FAQ)
1) 如何隱藏一列?
DataGridViewTextBoxColumn是一種通用的列類型,用於表示基於文本的值,好比數字和字符串。在編輯模式下,會有一個TextBox控件出如今當前活動單元格,用戶能夠修改單元格的值。
單元格的值在顯示時會自動轉換爲字符串。用戶輸入或修改的值在提交時則被自動解析爲合適的數據類型以建立一個單元格的值。經過處理CellFoamatting和CellParsing事件,你能夠自定義這些轉換的方式。好比將數據源的日期字段以特定的形式顯示,對某些特殊單元格做出特殊的標記。
對一列來講,它包含的單元格值的數據類型由該列的ValueType屬性指定。
2) Why does the cell text show up with 「square」 characters where they should be new lines?
DataGridViewCheckBoxColumn用於顯示Boolean或CheckState類型的值。Boolean 值顯示爲二元(two-state)或三元 (three-state) 的CheckBox,而這取決於該列的ThreeState 屬性的值。若是該類型的列綁定到CheckState類型的值,ThreeState屬性的默認值爲true。
通常狀況下,CheckBox類型的單元格要麼用於存儲數據,就像其它類型的數據同樣,要麼用於進行一些重要操做。用戶點擊CheckBox單元格時,若是你但願對此當即作出反應,能夠處理CellClick事件,但該事件發生在單元格的值更新以前。若是點擊之時就但願得到新值,一種選擇是根據當前值計算點擊後的值;另外一種方法是當即提交值的變化,而後在CellValueChanged事件處理函數中對此做出反應,而要在用戶點擊單元格時當即提交值的變化,你必須處理CurrentCellDirtyStateChanged事件,在這裏,調用CommitEnd方法提交新值。
DataGridViewImageColumn 類型的列用於顯示圖像。這種類型的列有三種方法生成:綁定到數據源時自動生成;爲非綁定列手動生成;在CellFormatting事件處理函數(該事件發生在單元格顯示前)中動態生成。
綁定到數據源時自動生成Image列的方法適用於大量的圖像格式,包括.NET中Image類支持的各類格式,還有Access數據庫及Northwind範例數據庫使用的OLE圖片格式。
若是你想提供DataGridViewButtonColumn列的功能,又但願顯示自定義的外觀,手動生成Image列會頗有用。在顯示後,你能夠處理CellClick事件以處理用戶對單元格的點擊(模擬按鈕列)。
若是你要爲計算值或非圖片的值提供圖片顯示,在CellFormatting事件處理函數中動態生成Image列的方法會頗有用。好比,你有一個表示風險值的列,它的值多是」high」、」middle」或」low」,能夠爲它們顯示不一樣的圖標做爲警示;或者你有一個名爲」Image」的列,它的值時圖片文件的位置而不是真實的圖片內容,也能夠用這種方法。
1) 如何使Image列不顯示任何圖像(字段值爲null時)?
使用DataGridViewButtonColumn 列,能夠在單元格內顯示按鈕。若是你要爲用戶操做特定行提供一種簡單的方式,Button列會頗有用,好比排序或在另外一個窗體中顯示子表記錄。
在對DataGridView進行數據綁定時不會自動生成Button列,因此你必須手動建立它們,而後把它們添加到DataGridView控件的Columns集合中。
你能夠處理CellClick事件以響應用戶的點擊動做。
在DataGridViewComboBoxColumn類型的列中,你能夠顯示包含下拉列表的單元格。這在僅容許用戶輸入一些特定值的時候顯得頗有用,好比在SQL Server示例數據庫Northwind中Products表的Category列,它表示產品的種類,這個應只容許選擇現有的產品種類,此時就可使用ComboBox列。
若是你瞭解如何爲ComboBox控件生成下拉列表,就能夠用相同的方式爲ComboBox列中的全部單元格生成下拉列表。要麼經過列的Items集合手動添加,要麼經過DataSource,DisplayMember 和ValueMember屬性綁定到一個數據源。要了解其中的更多信息,能夠參考WinForms中ComboBox空間的用法。
你能夠將ComboBox列的單元格的實際值綁定到DataGridView控件自己的數據源(注意不是ComboBox列的數據源),這須要設置該列的DataPropertyName屬性(設置某個列的名稱)。
ComboBox列不會在數據綁定時自動生成,因此你必須手動建立它們,而後將其添加到Columns集合屬性中。另外,你也可使用設計器,在設計時設置相應的屬性,這個過程相似於在設計器中ComboBox控件的使用。
在使用DataGridViewComboBoxColumn 時,有時會修改單元格的值或啓動ComboBox控件的Items集合,這樣可能會引起DataError事件。這是ComboBox列的設計使然,ComboBox列的單元格會進行數據驗證。在ComboBox列的單元格嘗試繪製包含的內容時,它須要將包含的值進行格式化(見第二章第三節),在此轉換過程當中,它會在ComboBox的Items集合中查找對應的值,若是查找失敗,就會引起DataError事件。忽略了DataError事件可能會使單元格不能進行正確的格式化。
2) How do I handle the SelectedIndexChanged event?
使用DataGridViewLinkColumn列,你能夠顯示一列包含超連接的單元格。在顯示數據源中的URL值,或者替代按鈕列進行一些特殊行爲,如打開另外一個子記錄窗體時會頗有用。
Link列也不會在DataGridView數據綁定時自動生成。要使用它,你還得手動建立,而後將它添加到DataGridView控件的Columns集合中。
你能夠處理CellContentClick事件來相應用戶的點擊動做。這個事件不一樣於CellClick 和CellMouseClick 事件,後二者在用戶點擊單元格任何位置(而不只僅時連接)時都會觸發。
DataGridViewLinkColumn 類提供了幾個屬性,用來修改連接的外觀,包括點擊前,點擊時和點擊後(相似於網頁中的超連接)。
多數狀況下,使用DataGridView的時候都須要跟數據打交道,這時有不少事情可能須要你去作。你須要驗證用戶輸入的數據,或者須要對數據進行格式化。DataGridView可以以三種模式顯示數據:bound、unboundand 和virtual。每種模式都有本身的特性和存在的理由。無論是不是數據綁定模式,在操做數據時,若是發生錯誤,DataGridView一般會觸發DataError事件,理解該事件發生的緣由能讓你更好地利用它。
用戶輸入數據時-對其所在的行或單元格,你可能但願驗證這些數據,在遇到無效數據時通知用戶。就像常見的Windows Forms控件,DataGridView的行和單元格也有Validating和Validated事件,驗證事件可被取消。用戶在單元格/行間移動時會觸發Enter和Leave事件。最後,用戶在開始編輯單元格時也會觸發事件。瞭解全部這些程序的發生順序會對你頗有幫助。
下面列出validation,enter/leave和begin/end這些事件的順序(當EditMode爲EditOnEnter時):
當從一個單元格移動至另外一單元格(在同一行內):
1) Cell Leave (原來的單元格)
2) Cell Validating/ed (原來的單元格)
3) Cell EndEdit (原來的單元格)
4) Cell Enter (新的單元格)
5) Cell BeginEdit (新的單元格)
當從一行移動到另外一行:
1) Cell Leave (原來的單元格),Row leave (原來的行)
2) Cell Validating/ed (原來的單元格)
3) Cell EndEdit (原來的單元格)
4) Row Validating/ed (原來的行)
5) Row Enter (新的行)
6) Cell Enter (新的單元格)
7) Cell BeginEdit (新的單元格)
驗證用戶輸入時,若是DataGridView採用非數據綁定模式,一般會對單元格進行驗證;而若是採用數據綁定模式,則通常會對行進行驗證。這與數據的組織方式密切相關,非數據綁定模式下,一行的單元格間關係通常比較「散」,而綁定模式下,數據源的數據通常以行來組織。但有時在數據綁定模式下會同時進行單元格級和行級的驗證。
一旦遭遇了無效的輸入數據,你一般須要通知用戶。這時有多種方式能夠選擇,傳統的方式是使用信息對話框。DataGridView還可以爲行或單元格顯示一個錯誤圖標來通知用戶輸入了無效數據。錯誤圖標帶有一個工具提示,它提供了該錯誤的相關信息:
當在程序中使用DataGridView來編輯數據時,你每每但願提供讓用戶添加新行數據的功能。DataGridView控件支持這個功能,提供了一個用於添加新記錄的行,而這一行老是顯示爲最後一行,並在該行的標題單元格標以星號(*)。 下面的幾個小節會討論一些在程序中使用這個新行時須要考慮的內容。(下面老是以 新行 表示 用於添加新記錄的行 )
使用AllowUserToAddRows屬性以指示是否顯示新行,其默認值爲true。
新行處於網格的最後一行,標題帶有星號:
在數據綁定的狀況下,當DataGridView控件的AllowUserToAddRows屬性和數據源的IBindingList.AllowNew 屬性都爲true時,新行纔會顯示,只要二者有一個爲false,新行就不會顯示。
當用戶選擇新行做爲當前行,DataGridView會觸發DefaultValuesNeeded事件。在該事件中能夠訪問新行,併爲其生成默認值,爲用戶輸入提供方便。
下面這段代碼演示瞭如何在DefaultValuesNeeded事件中爲新行指定默認值。
private void dataGridView1_DefaultValuesNeeded(object sender,
DataGridViewRowEventArgs e)
{
e.Row.Cells["Region"].Value = "WA";
e.Row.Cells["City"].Value = "Redmond";
e.Row.Cells["PostalCode"].Value = "98052-6399";
e.Row.Cells["Region"].Value = "NA";
e.Row.Cells["Country"].Value = "USA";
e.Row.Cells["CustomerID"].Value = NewCustomerId();
}
新行包含在DataGridView控件的Rows集合中,又因其老是處於最後一行,下面這行代碼會返回新行:
DataGridViewRow row = dataGridView1.Rows[dataGridView1.Rows.Count - 1];
儘管新行也包含在Rows集合中,它與Rows集合中其它行的行爲卻不相同,表如今兩點:
用戶開始在新行輸入數據以前,新行的IsNewRow屬性值爲true;一旦用戶開始輸入,這一行就再也不是新行了,DataGridView中會產生一個「新」的新行,看下面示意圖:
在添加「新」的新行時,會觸發UserAddedRow事件,它的事件處理函數的第二個參數有屬性Row,指定了這個「新」的新行。若是用戶此時按下Escape鍵,「新」的新行會被移除,這會觸發UserDeletingRow事件,它的事件處理函數的第二個參數的屬性Row指定了「新」的新行。
新行是基於RowTemplate模板建立的,若是沒有指定它的單元格的樣式,它們會採用繼承的樣式。要了解樣式繼承的更多信息,請參看第五章第一節的內容。
新行中單元格的初始值是由每一個單元格的DefaultNewRowValue屬性決定的。對於DataGridViewImageCell類型的單元格,其初始值爲一個佔位圖片,其它類型的則爲null。你能夠重寫這個屬性以返回自定義值。但也能夠在DefaultValuesNeeded事件處理函數中對默認值進行替換,該事件在焦點進入新行時觸發。
新行標題的標準圖標是箭頭或者星號,並無獲得暴露。若是你要自定義這個圖標,就須要建立一個自定義的DataGridViewRowHeaderCell 類。
新行的標題的標準圖標使用標題單元格DataGridViewCellStyle的ForeColor屬性。注意:若是沒有足夠的空間,圖標就不會再顯示。
若是爲標題單元格設置了字符串值(經過Value屬性),但沒有足夠的控件同時顯示文本和圖標,那麼圖標會被首先截掉。
在非綁定模式下,新行老是添加在DataGridView的最後一行,即便已經對數據排序。用戶須要在添加新行後再次進行排序,以將新記錄放在合適的位置;這種行爲方式相似於ListView控件。
在綁定模式或虛擬模式(Virtual Mode)下,若是已對數據排序,那麼插入數據時的行爲取決於數據模型的實現方式。對於ADO.NET,新加的行會被自動排序至合適的位置。
你不能將新行的Visible屬性值設置爲false,不然會觸發一個InvalidOperationException類型的異常。
新行在建立時老是處於非選中(unselected)狀態。
若是你正要實現虛擬模式(Virtual Mode),須要考慮數據模型添加新行和回滾添加操做的狀況。該功能準確的實現方式取決於數據模型的實現方式及其事務機制,例如,提交的時候是針對單元格仍是行。參看本文檔後面關於Virtual Mode的主題。
在使用數據源的時候,好比數據庫或業務對象,常常須要處理null值。null值多是一個實際的null(VB中爲Nothing),也多是一個數據庫的」null」值(DBNull.Value),當你遭遇了這些值,就須要考慮如何顯示它們。另外一方面,不少時候,你還須要向數據源寫入null值。使用單元格Style的NullValue屬性和DataSourceNullValue 屬性,你能夠改變DataGridView處理null值的方式。
DataGridViewCellStyle.NullValue 屬性原本要被命名爲FormattedNullValue 的,可是後來沒來得及做出這個更改。但它能給咱們帶來一點提示——顧名思義,在格式化時會用到它。若是一個單元格的值爲」null」(等於null或DBNull.Value),它會使用你設置的NullValue屬性來顯示。該屬性的默認值取決於所在列的類型,見下圖:
DataGridView列類型 |
列的DefaultCellStyle.NullValue值 |
TextBoxColumn |
String.Empty (「」) |
ImageColumn |
空的圖像( ) |
ComboBoxColumn |
String.Empty (「」) |
ButtonColumn |
String.Empty (「」) |
LinkColumn |
String.Empty (「」) |
CheckBoxColumn |
默認值取決於ThreeState屬性的值,若是爲true,默認值爲CheckState.Indeterminate ,不然爲unchecked。 |
有一點要了解,在用戶輸入數據時也會用到NullValue。例如,若用戶向TextBox類型單元格輸入了string.Empty,那麼會將null做爲該單元格的值。 查看下面的DataSourceNullValue屬性以瞭解到底是輸入了什麼做爲單元格的值。
DataGridViewCellStyle.DataSourceNullValue屬性要被命名爲ParseNullValue的,若是NullValue屬性被命名爲FormattedNullValue的話,但最後仍是採用了DataSourceNullValue,這樣更直觀準確。在將null值寫入單元格的值時,就會用到DataSourceNullValue屬性。在數據綁定情形下,這個null值將被寫入數據庫或業務對象,此處須要進行控制,由於對於數據庫和業務對象來講,null的概念不盡相同。一般你會指望,使用業務對象時將DataSourceNullValue 設置爲null,而使用數據庫時則將其設置爲DBNullValue。DataSourceNullValue的默認值爲DBNull.Value。
將DataError事件獨立出來做爲一個主題,是由於在操做數據時,常常會遭遇DataError事件。在操做數據時,DataError主要發生在一下狀況:不能讀/寫或轉換單元格的數據;在嘗試進行某種編輯操做時發生了異常。
編輯操做中的DataError 事件
下面的列表列出了可能會引起DataError事件的編輯操做:
|
|
|
|
|
|
|
DataError的上下文:
下面的列表顯示了不一樣的DataError上下文環境,而後進一步說明了這些上下文環境合適可能發生:
DataErrorContext |
什麼時候發生 |
Formatting |
When attempting to retrieve the cell's formatted value. |
Display |
When attempting to paint the cell or calculate the cell's tooltiptext. Note that these operations usually also require getting the cell's formatted value, so the error context is OR'd together. |
PreferredSize |
When calculating the preferred size of a cell. This |
RowDeletion |
Any exception raised when deleting a row. |
Parsing |
When exceptions occur when committing, ending or canceling an edit. Usually OR'd in with other error contexts |
Commit |
When exceptions occur when committing an edit. Usually OR'd with other error contexts |
InitialValueRestoration |
When exceptions occur while either initializing the editing control/cell's value, or Canceling an edit |
LeaveControl |
When exceptions occur while attempting to validate grid data when the grid is losing focus. Usually OR'd with other error contexts. |
CurrentCellChange |
When exceptions occur while validating\updating\committing\getting cell content when the current cell changes. Usually OR'd with other error contexts. |
Scroll |
When exceptions occur while validating\updating\committing\getting cell content when the current cell changes as a result of scrolling. |
ClipboardContent |
When exceptions occur while attempting to get the formatted value of a cell while creating the clipboard content. |
若是你要在程序中管理數量相對較小的數據,那麼非綁定模式會比較合適。此時你不是像綁定模式中那樣將DataGridView控件直接指向一個數據源,而是手動去生成控件。通常須要用到DataGridViewRowCollection.Add 方法(該方法向DGV中添加行)。
非綁定模式在處理靜態、只讀的數據時特別有用,也能夠用在以本身的方式與外部數據源交互的狀況,但實際上,若是你但願你的用戶與外部的數據源交互,通常仍是用綁定模式(bound mode)更好。
若是你在程序中管理一些數據,並但願能與數據源自動進行交互,就應該使用綁定模式。此時你能夠設置DataSource屬性,將數據源綁定到DataGridView控件。若是控件使用了綁定模式,就不須要你去顯式地對數據進行讀寫了。若是AutoGenerateColumns 屬性爲true,數據源中的每一列都會在DataGridView中生成一個相應的列(根據列的數據類型),若是你但願建立本身的列,能夠將該屬性設置爲false,使用DataPropertyName屬性將一列綁定到數據源的一列,這在你不想用自動生成的列類型時頗有用。
將數據綁定到DataGridView很是簡單、直觀,不少狀況下,你只須要設置它的DataSource屬性。若是使用的數據源包含多個列表(list)或數據表(table),你還須要設置控件的DataMember屬性,該屬性爲字符串類型,用於指定要綁定的列表或數據表。
DataGridView控件支持標準的WinForm數據綁定模型,所以它能夠綁定到下面列表中的類的實例:
列表更改通知(List Change Notification)
當你將數據綁定到列表時,最重要的功能之一即是支持列表更改通知了。這隻有在你但願列表(即數據源)發生變化,如添加、修改和刪除,DataGridView可以隨之更新的時候,該功能才顯得重要。只有實現了IBindingList接口的數據源支持更改通知。像數組和集合這樣的列表默認狀況下不支持更改通知。
在選擇數據源時,BindingSource組件應該做爲首選,由於它能夠綁定到多種類型的數據源,而且可以自動處理不少數據綁定相關的事務。通常狀況下,應該將DataGridView綁定到BindingSource組件,並將BindingSource組件綁定真正的數據源(它的做用就像DGV和數據源間的橋樑)。 BindingList<T>類也能夠在一個類的基礎上建立自定義列表(list)。
對象更改通知(Object Change Notification)
若是你有了一個數據源,那麼數據源中的對象就能夠實現對public屬性的更改通知。這須要你爲相應屬性提供一個」 PropertyNameChanged」事件,或者實現INotifyPropertyChanged接口。INotifyPropertyChanged 是在VS 2005 中新加的接口,能夠與BindingList<T>一塊兒使用來建立可綁定的列表(list)。但當你的數據源是BindingSource ,那就不用再額外實現更改通知了。
使用虛擬模式,你能夠實現本身的數據管理操做。在綁定模式下,若是要使用非綁定列,那麼要想在對列排序時可以維護非綁定列的值,就須要虛擬模式。但虛擬模式的最主要的用途仍是在操做大量數據時優化性能。
你將DataGridView綁定到緩存的數據,而後用代碼控制數據行的存取。要保持使用內存量比較小,緩存的數據量應與當前要顯示的行數至關。當用戶滾動控件看到了新的行時,你的代碼就從緩存中請求新的數據,並從內存中清除舊的數據。
若是你正要實現虛擬模式(Virtual Mode),須要考慮數據模型添加新行和回滾添加操做的狀況。該功能準確的實現方式取決於數據模型的實現方式及其事務機制,例如,提交的時候是針對單元格仍是行。參看本文檔後面關於Virtual Mode的主題。
顯示在DataGridView中的數據一般來自於某種類型的數據源,可是你可能也但願顯示一個數據源以外的列。這種列稱爲非綁定列。
你能夠在綁定模式下添加非綁定列,在你但願顯示一個按鈕列或者連接列讓用戶操做一些特定行時這顯得頗有用,另外也能夠用非綁定列顯示一些由綁定列計算而獲得的值。你能夠在CellFormatting事件處理函數中生成計算列的值。不過若是你使用的數據源是DataSet或DataTable,你可能但願使用DataColumn.Expression 屬性來建立一個計算列,在這種狀況下,在DGV看來,這一列就跟數據源中其它列是同樣的。
在綁定模式下根據非綁定列排序是不受支持的。若是你在綁定模式下建立了非綁定列,你必須實現虛擬模式,這樣在根據綁定列排序時能夠維護非綁定列的值。
若是添加的非綁定列不能由數據源數據計算得來或者這些數據會頻繁更新,你就應該使用虛擬模式。要了解虛擬模式的更多信息,請參看本文檔後面的虛擬模式相關章節。
2) How do I show data that comes from two tables?(TODO)
3) 如何顯示主從表?
5) 如何避免對一列的排序?
6) 如何針對多個列排序?
DataGridView使得定義單元格的基本外觀和格式化單元格顯示變得簡單。
您能夠定義的外觀和在特定的列和行,或在經過各類設置DataGridView控件屬性訪問的DataGridViewCellStyle對象的屬性控制全部細胞的單個單元格的格式樣式。此外,您能夠修改,如經過處理CellFormatting事件的單元格值因素的基礎上動態這些樣式。
DataGridView控件中的每個細胞均可以擁有如文本格式,背景色,前景色和字體本身的風格。可是,一般多個單元格將分享獨特的風格特色。
細胞羣體共享樣式可能包括在特定行或列的全部單元格包含特定值,或控件中的全部細胞的全部細胞。因爲這些羣體重疊,每一個單元可能會從多個位置的樣式信息。例如,您可能會但願每一個在DataGridView控件使用相同的字體細胞,只有細胞貨幣列,但使用貨幣格式,負數和貨幣細胞只使用紅色前景色。
You can define appearance and formatting styles for individual cells, for cells in specific columns and rows, or for all cells in the control by setting the properties of the DataGridViewCellStyle objects accessed through various DataGridView control properties. Additionally, you can modify these styles dynamically based on factors such as the cell value by handling the CellFormatting event.
Each cell within the DataGridView control can have its own style, such as text format, background color, foreground color, and font. Typically, however, multiple cells will share particular style characteristics.
Groups of cells that share styles may include all cells within particular rows or columns, all cells that contain particular values, or all cells in the control. Because these groups overlap, each cell may get its styling information from more than one place. For example, you may want every cell in a DataGridView control to use the same font, but only cells in currency columns to use currency format, and only currency cells with negative numbers to use a red foreground color.
The DataGridViewCellStyle class contains the following properties related to visual style:
BackColor and ForeColor, SelectionBackColor and SelectionForeColor, Font
This class also contains the following properties related to formatting:
Format and FormatProvider, NullValue and DataSourceNullValue, WrapMode, Alignment, Padding
DataGridViewCellStyle類包含如下有關視覺樣式屬性:
背景色和前景色,SelectionBackColor和SelectionForeColor,字體
此類還包含了相關的格式以下屬性:
格式和FormatProvider,並DataSourceNullValue的NullValue,的WrapMode,對齊,填充
You can retrieve DataGridViewCellStyle objects from various properties of the DataGridView, DataGridViewColumn, DataGridViewRow, and DataGridViewCell classes and their derived classes. If one of these properties has not yet been set, retrieving its value will create a new DataGridViewCellStyle object. You can also instantiate your own DataGridViewCellStyle objects and assign them to these properties.
You can avoid unnecessary duplication of style information by sharing DataGridViewCellStyle objects among multiple DataGridView elements. Because the styles set at the control, column, and row levels filter down through each level to the cell level, you can also avoid style duplication by setting only those style properties at each level that differ from the levels above. This is described in more detail in the Style Inheritance section that follows.
The following table lists the primary properties that get or set DataGridViewCellStyle objects.
Property |
Classes |
Description |
DefaultCellStyle |
DataGridView, DataGridViewColumn, DataGridViewRow, and derived classes |
Gets or sets default styles used by all cells in the entire control (including header cells), in a column, or in a row. |
RowsDefaultCellStyle |
DataGridView |
Gets or sets default cell styles used by all rows in the control. This does not include header cells. |
AlternatingRowsDefaultCellStyle |
DataGridView |
Gets or sets default cell styles used by alternating rows in the control. Used to create a ledger-like effect. |
RowHeadersDefaultCellStyle |
DataGridView |
Gets or sets default cell styles used by the control's row headers. Overridden by the current theme if visual styles are enabled. |
ColumnHeadersDefaultCellStyle |
DataGridView |
Gets or sets default cell styles used by the control's column headers. Overridden by the current theme if visual styles are enabled. |
Style |
DataGridViewCell and derived classes |
Gets or sets styles specified at the cell level. These styles override those inherited from higher levels. |
InheritedStyle |
DataGridViewCell, DataGridViewRow, DataGridViewColumn, and derived classes |
Gets all the styles currently applied to the cell, row, or column, including styles inherited from higher levels. |
As mentioned above, getting the value of a style property automatically instantiates a new DataGridViewCellStyle object if the property has not been previously set. To avoid creating these objects unnecessarily, the row and column classes have a HasDefaultCellStyle property that you can check to determine whether the DefaultCellStyle property has been set. Similarly, the cell classes have a HasStyle property that indicates whether the Style property has been set.
Each of the style properties has a corresponding PropertyNameChanged event on the DataGridView control. For row, column, and cell properties, the name of the event begins with "Row", "Column", or "Cell" (for example, RowDefaultCellStyleChanged). Each of these events occurs when the corresponding style property is set to a different DataGridViewCellStyle object. These events do not occur when you retrieve a DataGridViewCellStyle object from a style property and modify its property values. To respond to changes to the cell style objects themselves, handle the CellStyleContentChanged event.
Each DataGridViewCell gets its appearance from its InheritedStyle property. The DataGridViewCellStyle object returned by this property inherits its values from a hierarchy of properties of type DataGridViewCellStyle. These properties are listed below in the order in which the InheritedStyle for non-header cells obtains its values.
For row and column header cells, the InheritedStyle property is populated by values from the following list of source properties in the given order.
The following diagram illustrates this process.
You can also access the styles inherited by specific rows and columns. The column InheritedStyle property inherits its values from the following properties.
The row InheritedStyle property inherits its values from the following properties.
For each property in a DataGridViewCellStyle object returned by an InheritedStyle property, the property value is obtained from the first cell style in the appropriate list that has the corresponding property set to a value other than the DataGridViewCellStyle class defaults.
The following table illustrates how the ForeColor property value for an example cell is inherited from its containing column.
Property of type DataGridViewCellStyle |
Example ForeColor value for retrieved object |
DataGridViewCell.Style |
Color.Empty |
DataGridViewRow.DefaultCellStyle |
Color.Red |
AlternatingRowsDefaultCellStyle |
Color.Empty |
RowsDefaultCellStyle |
Color.Empty |
DataGridViewColumn.DefaultCellStyle |
Color.DarkBlue |
DefaultCellStyle |
Color.Black |
In this case, the System.Drawing.Color.Red value from the cell's row is the first real value on the list. This becomes the ForeColor property value of the cell's InheritedStyle.
The following diagram illustrates how different DataGridViewCellStyle properties can inherit their values from different places.
By taking advantage of style inheritance, you can provide appropriate styles for the entire control without having to specify the same information in multiple places.
Although header cells participate in style inheritance as described, the objects returned by the ColumnHeadersDefaultCellStyle and RowHeadersDefaultCellStyle properties of the DataGridView control have initial property values that override the property values of the object returned by the DefaultCellStyle property. If you want the properties set for the object returned by the DefaultCellStyle property to apply to row and column headers, you must set the corresponding properties of the objects returned by the ColumnHeadersDefaultCellStyle and RowHeadersDefaultCellStyle properties to the defaults indicated for the DataGridViewCellStyle class.
Note: If visual styles are enabled, the row and column headers (except for the TopLeftHeaderCell) are automatically styled by the current theme, overriding any styles specified by these properties. Set the EnableHeadersVisualStyle property to false if you want headers to not use XP’s visual styles.
The DataGridViewButtonColumn, DataGridViewImageColumn, and DataGridViewCheckBoxColumn types also initialize some values of the object returned by the column DefaultCellStyle property. For more information, see the reference documentation for these types.
To customize the styles of cells with particular values, implement a handler for the CellFormatting event. Handlers for this event receive an argument of the DataGridViewCellFormattingEventArgs type. This object contains properties that let you determine the value of the cell being formatted along with its location in the DataGridView control. This object also contains a CellStyle property that is initialized to the value of the InheritedStyle property of the cell being formatted. You can modify the cell style properties to specify style information appropriate to the cell value and location.
Note: The RowPrePaint and RowPostPaint events also receive a DataGridViewCellStyle object in the event data, but in their case, it is a copy of the row InheritedStyle property for read-only purposes, and changes to it do not affect the control.
You can also dynamically modify the styles of individual cells in response to events such as the CellMouseEnter and CellMouseLeave events. For example, in a handler for the CellMouseEnter event, you could store the current value of the cell background color (retrieved through the cell's Style property), then set it to a new color that will highlight the cell when the mouse hovers over it. In a handler for the CellMouseLeave event, you can then restore the background color to the original value.
Note: Caching the values stored in the cell's Style property is important regardless of whether a particular style value is set. If you temporarily replace a style setting, restoring it to its original "not set" state ensures that the cell will go back to inheriting the style setting from a higher level. If you need to determine the actual style in effect for a cell regardless of whether the style is inherited, use the cell's InheritedStyle property.
The DataGridView control provides several properties that you can use to adjust the appearance and basic behavior (look and feel) of its cells, rows, and columns. If you have requirements that go beyond the capabilities of the DataGridViewCellStyle class, you can perform custom drawing of the cell or row content. To paint cells and rows yourself, you can handle various DataGridView painting events such as RowPrePaint, CellPainting and RowPostPaint.
One important part of custom painting is the concept of paint parts. The DataGridViewPainParts enumeration is used to specify what parts a cell paints. Enum values can be combined together to have a cell paint or not paint specific parts. Here are the different parts:
PaintPart |
Example ForeColor value for retrieved object |
All |
All parts are painted |
Background |
The background of the cell is painted using the cell’s background color (1) |
Border |
The borders are painted |
ContentBackground |
The background part of the cell’s content is painted. (2) |
ContentForeground |
The foreground part of the cell’s content is painted (2) |
ErrorIcon |
The error icon is painted |
Focus |
The focus rectangle for the cell is painted |
None |
No parts are painted (1) |
SelectionBackground |
The background is painted selected if the cell is selected. |
Notes
1) If a cell does not paint its background then nothing is painted. A row or column performs no painting, so ensure that at least the cell’s background is painted or you perform your own custom background painting; otherwise the rectangle remains invalidated (unpainted).
2) Each cell determines what it paints as content foreground and content background as described by the following list:
Cell Type |
Content Foreground |
Content Background |
Text box |
Cell text is painted |
Nothing painted |
Button |
Cell text is painted |
Button is painted |
Combo box |
Cell text is painted |
Combo box is painted |
Check box |
Check box is painted |
Nothing painted |
Link |
Cell text is painted as a link |
Nothing is painted |
Image |
Cell image is painted |
Nothing painted |
Column Header |
Column header text |
Sort Glyph is painted |
Row Header |
Row header text |
Current row triangle, edit pencil and new row indicator is painted |
You can control the appearance of DataGridView rows by handling one or both of the DataGridView.RowPrePaint and DataGridView.RowPostPaint events. These events are designed so that you can paint only what you want to while letting the DataGridView control paint the rest. For example, if you want to paint a custom background, you can handle the DataGridView.RowPrePaint event and let the individual cells paint their own foreground content. In the RowPrePaint event you can set the PaintParts event args property to easily customize how the cells paint. For example, if you want to keep cells from painting any selection or focus, your RowPrePaint event would set the PaintParts property like so:
e.PaintParts = DataGridViewPaintParts.All &
~(DataGridViewPaintParts.Focus |
DataGridViewPaintParts.SelectionBackground);
Which could also be written as:
e.PaintParts = (DataGridViewPaintParts.Background |
DataGridViewPaintParts.Border |
DataGridViewPaintParts.ContentBackground |
DataGridViewPaintParts.ContentForeground |
DataGridViewPaintParts.ErrorIcon);
Alternately, you can let the cells paint themselves and add custom foreground content in a handler for the DataGridView.RowPostPaint event. You can also disable cell painting and paint everything yourself in a DataGridView.RowPrePaint event handler
The DataGridView control provides numerous options for customizing the sizing behavior of its columns and rows. Typically, DataGridView cells do not resize based on their contents. Instead, they clip any display value that is larger than the cell. If the content can be displayed as a string, the cell displays it in a ToolTip.
By default, users can drag row, column, and header dividers with the mouse to show more information. Users can also double-click a divider to automatically resize the associated row, column, or header band based on its contents. Columns share the available width of the control by default, so if users can resize the control—for example, if it is docked to a resizable form—they can also change the available display space for all columns.
The DataGridView control provides properties, methods, and events that enable you to customize or disable all of these user-directed behaviors. Additionally, you can programmatically resize rows, columns, and headers to fit their contents, or you can configure them to automatically resize themselves whenever their contents change.
常見問題:
DataGridView rows, columns, and headers can change size as a result of many different occurrences. The following table shows these occurrences.
Occurrence |
Description |
User resize |
Users can make size adjustments by dragging or double-clicking row, column, or header dividers. |
Control resize |
In column fill mode, column widths change when the control width changes; for example, when the control is docked to its parent form and the user resizes the form. |
Cell value change |
In content-based automatic sizing modes, sizes change to fit new display values. |
Method call |
Programmatic content-based resizing lets you make opportunistic size adjustments based on cell values at the time of the method call. |
Property setting |
You can also set specific height and width values. |
By default, user resizing is enabled, automatic sizing is disabled, and cell values that are wider than their columns are clipped.
The following table shows scenarios that you can use to adjust the default behavior or to use specific sizing options to achieve particular effects.
Scenario |
Implementation |
Use column fill mode for displaying similarly sized data in a relatively small number of columns that occupy the entire width of the control without displaying the horizontal scroll bar. |
Set the AutoSizeColumnsMode property to Fill. |
Use column fill mode with display values of varying sizes. |
Set the AutoSizeColumnsMode property to Fill. Initialize relative column widths by setting the column FillWeight properties or by calling the control AutoResizeColumns method after filling the control with data. |
Use column fill mode with values of varying importance. |
Set the AutoSizeColumnsMode property to Fill. Set large MinimumWidth values for columns that must always display some of their data or use a sizing option other than fill mode for specific columns. |
Use column fill mode to avoid displaying the control background. |
Set the AutoSizeMode property of the last column to Fill and use other sizing options for the other columns. |
Display a fixed-width column, such as an icon or ID column. |
Set AutoSizeMode to None and Resizable to False for the column. Initialize its width by setting the Width property or by calling the control AutoResizeColumn method after filling the control with data. |
Adjust sizes automatically whenever cell contents change to avoid clipping and to optimize the use of space. |
Set an automatic sizing property to a value that represents a content-based sizing mode. To avoid a performance penalty when working with large amounts of data, use a sizing mode that calculates displayed rows only. |
Adjust sizes to fit values in displayed rows to avoid performance penalties when working with many rows. |
Use the appropriate sizing-mode enumeration values with automatic or programmatic resizing. To adjust sizes to fit values in newly displayed rows while scrolling, call a resizing method in a Scroll event handler. To customize user double-click resizing so that only values in displayed rows determine the new sizes, call a resizing method in a RowDividerDoubleClick or ColumnDividerDoubleClick event handler. |
Adjust sizes to fit cell contents only at specific times to avoid performance penalties or to enable user resizing. |
Call a content-based resizing method in an event handler. For example, use the DataBindingComplete event to initialize sizes after binding, and handle the CellValidated or CellValueChanged event to adjust sizes to compensate for user edits or changes in a bound data source. |
Adjust row heights for multiline cell contents. |
Ensure that column widths are appropriate for displaying paragraphs of text and use automatic or programmatic content-based row sizing to adjust the heights. Also ensure that cells with multiline content are displayed using a WrapMode cell style value of True. Typically, you will use an automatic column sizing mode to maintain column widths or set them to specific widths before row heights are adjusted. |
By default, users can resize rows, columns, and headers that do not use an automatic sizing mode based on cell values. To prevent users from resizing with other modes, such as column fill mode, set one or more of the following DataGridView properties:
You can also prevent users from resizing individual rows or columns by setting their Resizable properties. By default, the Resizable property value is based on the AllowUserToResizeColumns property value for columns and the AllowUserToResizeRows property value for rows. If you explicitly set Resizable to True or False, however, the specified value overrides the control value is for that row or column. Set Resizable to NotSet to restore the inheritance.
Because NotSet restores the value inheritance, the Resizable property will never return a NotSet value unless the row or column has not been added to a DataGridView control. If you need to determine whether the Resizable property value of a row or column is inherited, examine its State property. If the State value includes the ResizableSet flag, the Resizable property value is not inherited.
There are two kinds of automatic sizing in the DataGridView control: column fill mode and content-based automatic sizing.
Column fill mode causes the visible columns in the control to fill the width of the control's display area. For more information about this mode, see the Column Fill Mode section below.
You can also configure rows, columns, and headers to automatically adjust their sizes to fit their cell contents. In this case, size adjustment occurs whenever cell contents change.
Note: If you maintain cell values in a custom data cache using virtual mode, automatic sizing occurs when the user edits a cell value but does not occur when you alter a cached value outside of a CellValuePushed event handler. In this case, call the UpdateCellValue method to force the control to update the cell display and apply the current automatic sizing modes.
If content-based automatic sizing is enabled for one dimension only—that is, for rows but not columns, or for columns but not rows—and WrapMode is also enabled, size adjustment also occurs whenever the other dimension changes. For example, if rows but not columns are configured for automatic sizing and WrapMode is enabled, users can drag column dividers to change the width of a column and row heights will automatically adjust so that cell contents are still fully displayed.
If you configure both rows and columns for content-based automatic sizing and WrapMode is enabled, the DataGridView control will adjust sizes whenever cell contents changed and will use an ideal cell height-to-width ratio when calculating new sizes.
To configure the sizing mode for headers and rows and for columns that do not override the control value, set one or more of the following DataGridView properties:
To override the control's column sizing mode for an individual column, set its AutoSizeMode property to a value other than NotSet. The sizing mode for a column is actually determined by its InheritedAutoSizeMode property. The value of this property is based on the column's AutoSizeMode property value unless that value is NotSet, in which case the control's AutoSizeColumnsMode value is inherited.
Use content-based automatic resizing with caution when working with large amounts of data. To avoid performance penalties, use the automatic sizing modes that calculate sizes based only on the displayed rows rather than analyzing every row in the control. For maximum performance, use programmatic resizing instead so that you can resize at specific times, such as immediately after new data is loaded.
Content-based automatic sizing modes do not affect rows, columns, or headers that you have hidden by setting the row or column Visible property or the control RowHeadersVisible or ColumnHeadersVisible properties to false. For example, if a column is hidden after it is automatically sized to fit a large cell value, the hidden column will not change its size if the row containing the large cell value is deleted. Automatic sizing does not occur when visibility changes, so changing the column Visible property back to true will not force it to recalculate its size based on its current contents.
Programmatic content-based resizing affects rows, columns, and headers regardless of their visibility.
When automatic sizing is disabled, you can programmatically set the exact width or height of rows, columns, or headers through the following properties:
You can also programmatically resize rows, columns, and headers to fit their contents using the following methods:
These methods will resize rows, columns, or headers once rather than configuring them for continuous resizing. The new sizes are automatically calculated to display all cell contents without clipping. When you programmatically resize columns that have InheritedAutoSizeMode property values of Fill, however, the calculated content-based widths are used to proportionally adjust the column FillWeight property values, and the actually column widths are then calculated according to these new proportions so that all columns fill the available display area of the control.
Programmatic resizing is useful to avoid performance penalties with continuous resizing. It is also useful to provide initial sizes for user-resizable rows, columns, and headers, and for column fill mode.
You will typically call the programmatic resizing methods at specific times. For example, you might programmatically resize all columns immediately after loading data, or you might programmatically resize a specific row after a particular cell value has been modified.
You can customize sizing behaviors when working with derived DataGridView cell, row, and column types by overriding the DataGridViewCell.GetPreferredSize(), DataGridViewRow.GetPreferredHeight(), or DataGridViewColumn.GetPreferredWidth() methods or by calling protected resizing method overloads in a derived DataGridView control. The protected resizing method overloads are designed to work in pairs to achieve an ideal cell height-to-width ratio, avoiding overly wide or tall cells. For example, if you call the AutoResizeRows(DataGridViewAutoSizeRowsMode,Boolean) overload of the AutoResizeRows method and pass in a value of false for the Boolean parameter, the overload will calculate the ideal heights and widths for cells in the row, but it will adjust the row heights only. You must then call the AutoResizeColumns method to adjust the column widths to the calculated ideal.
The enumerations used by sizing properties and methods have similar values for content-based sizing. With these values, you can limit which cells are used to calculate the preferred sizes. For all sizing enumerations, values with names that refer to displayed cells limit their calculations to cells in displayed rows. Excluding rows is useful to avoid a performance penalty when you are working with a large quantity of rows. You can also restrict calculations to cell values in header or nonheader cells.
The DataGridView control provides you with a variety of options for configuring how users can select cells, rows, and columns. For example, you can enable single or multiple selection, selection of whole rows or columns when users click cells, or selection of whole rows or columns only when users click their headers, which enables cell selection as well. If you want to provide your own user interface for selection, you can disable ordinary selection and handle all selection programmatically. Additionally, you can enable users to copy the selected values to the Clipboard.
Sometimes you want your application to perform actions based on user selections within a DataGridView control. Depending on the actions, you may want to restrict the kinds of selection that are possible. For example, suppose your application can print a report for the currently selected record. In this case, you may want to configure the DataGridView control so that clicking anywhere within a row always selects the entire row, and so that only one row at a time can be selected.
You can specify the selections allowed by setting the SelectionMode property to one of the following DataGridViewSelectionMode enumeration values.
DataGridViewSelectionMode value |
Description |
CellSelect |
單擊單元格以選中它,行列標題不能用於選擇。 |
ColumnHeaderSelect |
單擊單元格以選中它,單擊列標題選中整列。此時列標題不能用於排序。 |
FullColumnSelect |
單擊單元格或列標題會選中它們所在的列,此時列標題不能用於排序。 |
FullRowSelect |
單擊單元格或行標題會選中它們所在的行。 |
RowHeaderSelect |
DGV的默認選擇模式,單擊單元格選中該單元格,單擊行標題則選中整行。 |
注意: 在運行時改變選擇模式會自動清除當前選擇的內容。
By default, users can select multiple rows, columns, or cells by dragging with the mouse, pressing CTRL or SHIFT while selecting to extend or modify a selection, or clicking the top-left header cell to select all cells in the control. To prevent this behavior, set the MultiSelect property to false.
The FullRowSelect and RowHeaderSelect modes allow users to delete rows by selecting them and pressing the DELETE key. Users can delete rows only when the current cell is not in edit mode, the AllowUserToDeleteRows property is set to true, and the underlying data source supports user-driven row deletion. Note that these settings do not prevent programmatic row deletion.
The current selection mode restricts the behavior of programmatic selection as well as user selection. You can change the current selection programmatically by setting the Selected property of any cells, rows, or columns present in the DataGridView control. You can also select all cells in the control through the SelectAll method, depending on the selection mode. To clear the selection, use the ClearSelection method.
If the MultiSelect property is set to true, you can add DataGridView elements to or remove them from the selection by changing the Selected property of the element. Otherwise, setting the Selected property to true for one element automatically removes other elements from the selection.
注意:改變CurrentCell屬性的值不會改變當前選擇的內容。
經過SelectedCells、SelectedRows和SelectedColumns屬性你能夠訪問當前選中的單元格、行和列。不過當全部單元格都被選中的時候,使用這些屬性效率會比較低,爲此可首先使用AreAllCellsSelected方法查看是否已選中所有單元格。此外,訪問這些屬性來查看選中單元格、行和列的數目效率也比較低,此時應該使用GetCellCount、GetRowCount和GetColumnCount方法,傳給它們的參數爲DataGridViewElementStates.Selected。
DataGridView毫無疑問地會提供對水平和垂直滾動條的支持,它同時也支持使用鼠標滾輪進行垂直滾動。水平方向的滾動基於像素值,而垂直方向的滾動則基於行的索引,DataGridView不支持垂直方向的基於像素值的滾動。
As you scroll the DataGridView raises the Scroll event that allows you to be notified that scrolling is occurring. The Orientation property on the scroll event args lets you know the scroll direction.
The DataGridView provides access to the scrollbars that it displays via the protected HorizontalScrollBar and VerticalScrollBar properties. Accessing these ScrollBar controls directly allow you to have finer control over scrolling.
There are a set of properties that provide greater level of details on how the DataGridView is scrolled. The diagram highlights these properties and their values at this state. The properties are read/write except for the FirstDisplayedScrollingColumnHiddenWidth and VerticalScrollingOffset properties.
By default, users can sort the data in a DataGridView control by clicking the header of a text box column. You can modify the SortMode property of specific columns to allow users to sort by other column types when it makes sense to do so. You can also sort the data programmatically by any column, or by multiple columns.
DataGridView columns have three sort modes. The sort mode for each column is specified through the SortMode property of the column, which can be set to one of the following DataGridViewColumnSortMode enumeration values.
DataGridViewColumnSortMode value |
Description |
Automatic |
Default for text box columns. Unless column headers are used for selection, clicking the column header automatically sorts the DataGridView by this column and displays a glyph indicating the sort order. |
NotSortable |
Default for non–text box columns. You can sort this column programmatically; however, it is not intended for sorting, so no space is reserved for the sorting glyph. |
Programmatic |
You can sort this column programmatically, and space is reserved for the sorting glyph. |
You might want to change the sort mode for a column that defaults to NotSortable if it contains values that can be meaningfully ordered. For example, if you have a database column containing numbers that represent item states, you can display these numbers as corresponding icons by binding an image column to the database column. You can then change the numerical cell values into image display values in a handler for the CellFormatting event. In this case, setting the SortMode property to Automatic will enable your users to sort the column. Automatic sorting will enable your users to group items that have the same state even if the states corresponding to the numbers do not have a natural sequence. Check box columns are another example where automatic sorting is useful for grouping items in the same state.
You can sort a DataGridView programmatically by the values in any column or in multiple columns, regardless of the SortMode settings. Programmatic sorting is useful when you want to provide your own user interface (UI) for sorting or when you want to implement custom sorting. Providing your own sorting UI is useful, for example, when you set the DataGridView selection mode to enable column header selection. In this case, although the column headers cannot be used for sorting, you still want the headers to display the appropriate sorting glyph, so you would set the SortMode property to Programmatic.
Columns set to programmatic sort mode do not automatically display a sorting glyph. For these columns, you must display the glyph yourself by setting the DataGridViewColumnHeaderCell.SortGlyphDirection property. This is necessary if you want flexibility in custom sorting. For example, if you sort the DataGridView by multiple columns, you might want to display multiple sorting glyphs or no sorting glyph.
Although you can programmatically sort a DataGridView by any column, some columns, such as button columns, might not contain values that can be meaningfully ordered. For these columns, a SortMode property setting of NotSortable indicates that it will never be used for sorting, so there is no need to reserve space in the header for the sorting glyph.
When a DataGridView is sorted, you can determine both the sort column and the sort order by checking the values of the SortedColumn and SortOrder properties. These values are not meaningful after a custom sorting operation. For more information about custom sorting, see the Custom Sorting section later in this topic.
When a DataGridView control containing both bound and unbound columns is sorted, the values in the unbound columns cannot be maintained automatically. To maintain these values, you must implement virtual mode by setting the VirtualMode property to true and handling the CellValueNeeded and CellValuePushed events.
You can sort a DataGridView programmatically by calling its Sort method.
The Sort(DataGridViewColumn,ListSortDirection) overload of the Sort method takes a DataGridViewColumn and a ListSortDirection enumeration value as parameters. This overload is useful when sorting by columns with values that can be meaningfully ordered, but which you do not want to configure for automatic sorting. When you call this overload and pass in a column with a SortMode property value of DataGridViewColumnSortMode.Automatic, the SortedColumn and SortOrder properties are set automatically and the appropriate sorting glyph appears in the column header.
Note: When the DataGridView control is bound to an external data source by setting the DataSource property, the Sort(DataGridViewColumn,ListSortDirection) method overload does not work for unbound columns. Additionally, when the VirtualMode property is true, you can call this overload only for bound columns. To determine whether a column is data-bound, check the IsDataBound property value. Sorting unbound columns in bound mode is not supported.
You can customize DataGridView by using the Sort(IComparer) overload of the Sort method or by handling the SortCompare event.
The Sort(IComparer) method overload takes an instance of a class that implements the IComparer interface as a parameter. This overload is useful when you want to provide custom sorting; for example, when the values in a column do not have a natural sort order or when the natural sort order is inappropriate. In this case, you cannot use automatic sorting, but you might still want your users to sort by clicking the column headers. You can call this overload in a handler for the ColumnHeaderMouseClick event if you do not use column headers for selection.
Note: The Sort(IComparer) method overload works only when the DataGridView control is not bound to an external data source and the VirtualMode property value is false. To customize sorting for columns bound to an external data source, you must use the sorting operations provided by the data source. In virtual mode, you must provide your own sorting operations for unbound columns.
To use the Sort(IComparer) method overload, you must create your own class that implements the IComparer interface. This interface requires your class to implement the IComparer.Compare(Object) method, to which the DataGridView passes DataGridViewRow objects as input when the Sort(IComparer) method overload is called. With this, you can calculate the correct row ordering based on the values in any column.
The Sort(IComparer) method overload does not set the SortedColumn and SortOrder properties, so you must always set the DataGridViewColumnHeaderCell.SortGlyphDirection property to display the sorting glyph.
As an alternative to the Sort(IComparer) method overload, you can provide custom sorting by implementing a handler for the SortCompare event. This event occurs when users click the headers of columns configured for automatic sorting or when you call the Sort(DataGridViewColumn,ListSortDirection) overload of the Sort method. The event occurs for each pair of rows in the control, enabling you to calculate their correct order.
Note: The SortCompare event does not occur when the DataSource property is set or when the VirtualMode property value is true.
1) 如何避免用戶對列排序?
2) 如何針對多個列排序?
With the DataGridView control, you can customize the appearance of the control's border and gridlines to improve the user experience. You can modify the gridline color and the control border style in addition to the border styles for the cells within the control. The gridline color is controlled via the GridColor property. You can also apply different cell border styles for ordinary cells, row header cells, and column header cells. For advanced border styles the DataGridView provides the advanced border style properties as well.
Note: The gridline color is used only with the Single, SingleHorizontal, and SingleVertical values of the DataGridViewCellBorderStyle enumeration and the Single value of the DataGridViewHeaderBorderStyle enumeration. The other values of these enumerations use colors specified by the operating system. Additionally, when visual styles are enabled on Windows XP and above, the GridColor property value is not used.
Standard border styles are controlled via the CellBorderStyle, RowHeadersBorderStyle, and ColumnHeadersBorderStyle properties.
The following table identifies the standard border styles available via the :
BorderStyle value |
Description |
Fixed3D |
A three-dimensional border. |
FixedSingle |
A single-line border. |
None |
No border. |
The DataGridView control allows you to fully customize its appearance, including the borders of the cells and headers. The DataGridView has CellBorderStyle, ColumnHeadersBorderStyle, and RowHeadersBorderStyle properties that allow you to set the appearance of the cell border. However, if you need to further customize the borders, the DataGridViewAdvancedBorderStyle class allows you to set the style of the border on the individual sides of the cells. The Left, Right, Top, and Bottom properties of DataGridViewAdvancedBorderStyle represent the left, right, top, and bottom border of a cell, respectively. You can set these properties on the AdvancedCellBorderStyle, AdvancedColumnHeadersBorderStyle, AdvancedRowHeadersBorderStyle properties of the DataGridView to produce various appearances for the borders between the cells.
The following table identifies the advanced border styles available that can be set for the left, right, top and bottom parts. Note that some combinations are not valid.
BorderStyle value |
Description |
Inset |
A three-dimensional border. |
InsetDouble |
A single-line border. |
None |
No border. |
NotSet |
The border is not set |
Outset |
A single-line raised border |
OutsetDouble |
A double-line raised border |
OutsetPartial |
A single-line border containing a raised portion |
Single |
A single-line border |
By default, users can edit the contents of the current DataGridView text box cell by typing in it or pressing F2. This puts the cell in edit mode if all of the following conditions are met:
In edit mode, the user can change the cell value and press ENTER to commit the change or ESC to revert the cell to its original value.
You can configure a DataGridView control so that a cell enters edit mode as soon as it becomes the current cell. The behavior of the ENTER and ESC keys is unchanged in this case, but the cell remains in edit mode after the value is committed or reverted. You can also configure the control so that cells enter edit mode only when users type in the cell or only when users press F2. Finally, you can prevent cells from entering edit mode except when you call the BeginEdit method.
The following table describes the different edit modes available:
EditMode value |
Description |
EditOnEnter |
Editing begins when the cell receives focus. This mode is useful when pressing the TAB key to enter values across a row, or when pressing the ENTER key to enter values down a column. |
EditOnF2 |
Editing begins when F2 is pressed while the cell has focus. This mode places the selection point at the end of the cell contents. |
EditOnKeystroke |
Editing begins when any alphanumeric key is pressed while the cell has focus. |
EditOnKeystrokeOrF2 |
Editing begins when any alphanumeric key or F2 is pressed while the cell has focus. |
EditProgrammatically |
Editing begins only when the BeginEdit method is called. |
When you enable cell copying, you make the data in your DataGridView control easily accessible to other applications through the Clipboard. The DataGridView control copies the text representation of each selected cell to the Clipboard. This value is the cell value converted to a string or, for image cells, the value of the Description property. The content is then added to the Clipboard as tab-delimited text values for pasting into applications like Notepad and Excel, and as an HTML-formatted table for pasting into applications like Word.
You can configure cell copying to copy cell values only, to include row and column header text in the Clipboard data, or to include header text only when users select entire rows or columns.
The following table identifies the different clipboard copy modes:
Clipboard Copy modes |
Description |
Disable |
Copying to the Clipboard is disabled. |
EnableAlwaysIncludeHeaderText |
The text values of selected cells can be copied to the Clipboard. Header text is included for rows and columns that contain selected cells. |
EnableWithAutoHeaderText |
The text values of selected cells can be copied to the Clipboard. Row or column header text is included for rows or columns that contain selected cells only when the SelectionMode property is set to RowHeaderSelect or ColumnHeaderSelect and at least one header is selected. |
EnableWithoutHeaderText |
The text values of selected cells can be copied to the Clipboard. Header text is not included. |
Depending on the selection mode, users can select multiple disconnected groups of cells. When a user copies cells to the Clipboard, rows and columns with no selected cells are not copied. All other rows or columns become rows and columns in the table of data copied to the Clipboard. Unselected cells in these rows or columns are copied as blank placeholders to the Clipboard.
When users copy content, the DataGridView control adds a DataObject to the Clipboard. This data object is retrieved from the GetClipboardContent() method. You can call this method when you want to programmatically add the data object to the Clipboard. The GetClipboardContent() method retrieves values for individual cells by calling the DataGridViewCell.GetClipboardContent() method. You can override either or both of these methods in derived classes to customize the layout of copied cells or to support additional data formats.
When users view data sometimes they need to refer to a single column or set of columns frequently. For example, when displaying a table of customer information that contains many columns, it is useful to display the customer name at all times while enabling other columns to scroll outside the visible region.
To achieve this behavior, you can freeze columns in the control. This is done via setting the Frozen property on the column or row. When you freeze a column, all the columns to its left (or to its right in right-to-left language scripts) are frozen as well. Frozen columns remain in place while all other columns can scroll. Rows act in similar fashion: all rows before the frozen row are frozen as well and remain in place while the non frozen rows can scroll.
You can implement the IDataGridViewEditingCell interface in your derived cell class to create a cell type that has editing functionality but does not host a control in editing mode. To create a control that you can host in a cell in editing mode, you can implement the IDataGridViewEditingControl interface in a class derived from Control.
Cells that support advanced editing functionality typically use a hosted control that is derived from a Windows Forms control. This interface is implemented by editing controls, such as DataGridViewComboBoxEditingControl and DataGridViewTextBoxEditingControl, that are hosted by the corresponding DataGridView cells, such as DataGridViewComboBoxCell and DataGridViewTextBoxCell, when they are in edit mode.
Cell types that can that host editing controls set their EditType property to a Type representing the editing control type.
This interface is implemented by classes to provide a user interface (UI) for specifying values without hosting an editing control. The UI in this case is displayed regardless of whether the cell is in edit mode. The DataGridViewCheckBoxCell is an example of a cell that implements the IDataGridViewEditingCell interface.
Other cell types, such as DataGridViewButtonCell, provide a UI but do not store user-specified values. In this case, the cell type does not implement IDataGridViewEditingCell or host an editing control.
With virtual mode, you can manage the interaction between the DataGridView control and a custom data cache. To implement virtual mode, set the VirtualMode property to true and handle one or more of the events described in this topic. You will typically handle at least the CellValueNeeded event, which enables the control look up values in the data cache.
Virtual mode is necessary only when you need to supplement or replace bound mode. In bound mode, you set the DataSource property and the control automatically loads the data from the specified source and submits user changes back to it. You can control which of the bound columns are displayed, and the data source itself typically handles operations such as sorting.
You can supplement bound mode by displaying unbound columns along with the bound columns. This is sometimes called "mixed mode" and is useful for displaying things like calculated values or user-interface (UI) controls.
Because unbound columns are outside the data source, they are ignored by the data source's sorting operations. Therefore, when you enable sorting in mixed mode, you must manage the unbound data in a local cache and implement virtual mode to let the DataGridView control interact with it.
1) How do I show unbound data along with bound data?
2) How do I show data that comes from two tables?
If bound mode does not meet your performance needs, you can manage all your data in a custom cache through virtual-mode event handlers. For example, you can use virtual mode to implement a just-in-time data loading mechanism that retrieves only as much data from a networked database as is necessary for optimal performance. This scenario is particularly useful when working with large amounts of data over a slow network connection or with client machines that have a limited amount of RAM or storage space.
If your data is read-only, the CellValueNeeded event may be the only event you will need to handle. Additional virtual-mode events let you enable specific functionality like user edits, row addition and deletion, and row-level transactions.
Some standard DataGridView events (such as events that occur when users add or delete rows, or when cell values are edited, parsed, validated, or formatted) are useful in virtual mode, as well. You can also handle events that let you maintain values not typically stored in a bound data source, such as cell ToolTip text, cell and row error text, cell and row shortcut menu data, and row height data.
The following events occur only when the VirtualMode property is set to true.
Event |
Description |
CellValueNeeded |
Used by the control to retrieve a cell value from the data cache for display. This event occurs only for cells in unbound columns. |
CellValuePushed |
Used by the control to commit user input for a cell to the data cache. This event occurs only for cells in unbound columns. Call the UpdateCellValue method when changing a cached value outside of a CellValuePushed event handler to ensure that the current value is displayed in the control and to apply any automatic sizing modes currently in effect. |
NewRowNeeded |
Used by the control to indicate the need for a new row in the data cache. |
RowDirtyStateNeeded |
Used by the control to determine whether a row has any uncommitted changes. |
CancelRowEdit |
Used by the control to indicate that a row should revert to its cached values. |
The following events are useful in virtual mode, but can be used regardless of the VirtualMode property setting.
Events |
Description |
UserDeletingRow UserDeletedRow RowsRemoved RowsAdded |
Used by the control to indicate when rows are deleted or added, letting you update the data cache accordingly. |
CellFormatting CellParsing CellValidating CellValidated RowValidating RowValidated |
Used by the control to format cell values for display and to parse and validate user input. |
CellToolTipTextNeeded |
Used by the control to retrieve cell ToolTip text when the DataSource property is set or the VirtualMode property is true. Cell ToolTips are displayed only when the ShowCellToolTips property value is true. |
CellErrorTextNeeded RowErrorTextNeeded |
Used by the control to retrieve cell or row error text when the DataSource property is set or the VirtualMode property is true. Call the UpdateCellErrorText method or the UpdateRowErrorText method when you change the cell or row error text to ensure that the current value is displayed in the control. Cell and row error glyphs are displayed when the ShowCellErrors and ShowRowErrors property values are true. |
CellContextMenuStripNeeded RowContextMenuStripNeeded |
Used by the control to retrieve a cell or row ContextMenuStrip when the control DataSource property is set or the VirtualMode property is true. |
RowHeightInfoNeeded RowHeightInfoPushed |
Used by the control to retrieve or store row height information in the data cache. Call the UpdateRowHeightInfo method when changing the cached row height information outside of a RowHeightInfoPushed event handler to ensure that the current value is used in the display of the control. |
If you are implementing virtual mode in order to work efficiently with large amounts of data, you will also want to ensure that you are working efficiently with the DataGridView control itself. See below for more information on best practices
In general, the DataGridView does not have any hard-coded capacity limits. The grid was designed so that more and more content can be added as machines become faster and have more memory. That said, the grid was not designed to deal with large number of columns. If you add more than 300 columns you will start to notice a degradation in performance as our performance tuning of the grid was not designed for this. If you need a grid with large amounts of columns then the DataGridView might not meet your needs. Regarding the number of rows supported, the DataGridView is bound by memory constraints. When using Virtual mode you can easily support over 2 million rows. Check out the best practices section below for information on things you can do (and not do) to improve memory usage and performance.
The DataGridView control is designed to provide maximum scalability. If you need to display large amounts of data, you should follow the guidelines described in this topic to avoid consuming large amounts of memory or degrading the responsiveness of the user interface (UI).
Each cell, row, and column can have its own style information. Style information is stored in DataGridViewCellStyle objects. Creating cell style objects for many individual DataGridView elements can be inefficient, especially when working with large amounts of data. To avoid a performance impact, use the following guidelines:
Each cell, row, and column can have its own shortcut menu. Shortcut menus in the DataGridView control are represented by ContextMenuStrip controls. Just as with cell style objects, creating shortcut menus for many individual DataGridView elements will negatively impact performance. To avoid this penalty, use the following guidelines:
Rows, columns, and headers can be automatically resized as cell content changes so that the entire contents of cells are displayed without clipping. Changing sizing modes can also resize rows, columns, and headers. To determine the correct size, the DataGridView control must examine the value of each cell that it must accommodate. When working with large data sets, this analysis can negatively impact the performance of the control when automatic resizing occurs. To avoid performance penalties, use the following guidelines:
The SelectedCells collection does not perform efficiently with large selections. The SelectedRows and SelectedColumns collections can also be inefficient, although to a lesser degree because there are many fewer rows than cells in a typical DataGridView control, and many fewer columns than rows. To avoid performance penalties when working with these collections, use the following guidelines:
Efficient memory use is achieved in the DataGridView control through shared rows. Rows will share as much information about their appearance and behavior as possible by sharing instances of the DataGridViewRow class.
While sharing row instances saves memory, rows can easily become unshared. For example, whenever a user interacts directly with a cell, its row becomes unshared. Because this cannot be avoided, the guidelines in this topic are useful only when working with very large amounts of data and only when users will interact with a relatively small part of the data each time your program is run.
A row cannot be shared in an unbound DataGridView control if any of its cells contain values. When the DataGridView control is bound to an external data source or when you implement virtual mode and provide your own data source, the cell values are stored outside the control rather than in cell objects, allowing the rows to be shared.
A row object can only be shared if the state of all its cells can be determined from the state of the row and the states of the columns containing the cells. If you change the state of a cell so that it can no longer be deduced from the state of its row and column, the row cannot be shared.
For example, a row cannot be shared in any of the following situations:
In bound mode or virtual mode, you can provide ToolTips and shortcut menus for individual cells by handling the CellToolTipTextNeeded and CellContextMenuStripNeeded events.
The DataGridView control will automatically attempt to use shared rows whenever rows are added to the DataGridViewRowCollection. Use the following guidelines to ensure that rows are shared:
To determine whether a row is shared, use the DataGridViewRowCollection.SharedRow(Int) method to retrieve the row object, and then check the object's Index property. Shared rows always have an Index property value of –1.
Shared rows can become unshared as a result of code or user action. To avoid a performance impact, you should avoid causing rows to become unshared. During application development, you can handle the RowUnshared event to determine when rows become unshared. This is useful when debugging row-sharing problems.
To prevent rows from becoming unshared, use the following guidelines:
你能夠檢索各類屬性的DataGridView,DataGridViewColumn的,的DataGridViewRow,和DataGridViewCell類及其派生類DataGridViewCellStyle對象。若是其中一個屬性還沒有設置,檢索其值將建立一個新的DataGridViewCellStyle對象。您還能夠將本身的DataGridViewCellStyle對象,並將它們分配給這些屬性。
您能夠經過共享的DataGridViewCellStyle避免沒必要要的在多個DataGridView元素對象的樣式信息的重複。由於在控制,列集的風格,和行各層面滲透到細胞水平的水平了,你還能夠經過設置避免只在每一個級別,從不一樣層次上的風格樣式屬性重複。這是進行了更詳細的樣式繼承節以下。
下表列出了獲取或設置DataGridViewCellStyle對象的主要屬性。
物業類的描述
的DefaultCellStyle的DataGridView,DataGridViewColumn的,的DataGridViewRow和派生類獲取或設置全部單元格中使用的整個控制(包括標題單元格)的默認風格,在一列,或在一排。
RowsDefaultCellStyle的DataGridView獲取或設置默認單元格的控件中的全部行使用的樣式。這不包括標題單元格。
AlternatingRowsDefaultCellStyle的DataGridView獲取或設置默認單元格的行交替使用的樣式的控制。用於建立一個總帳般的效果。
RowHeadersDefaultCellStyle的DataGridView獲取或設置該控件的默認單元格的行標題使用的樣式。由當前主題重寫若是啓用視覺樣式。
ColumnHeadersDefaultCellStyle的DataGridView獲取或設置該控件的默認單元格的列標題使用的樣式。由當前主題重寫若是啓用視覺樣式。
風格的DataGridViewCell和派生類獲取或設置在細胞水平上指定的樣式。這些樣式覆蓋上級繼承的。
InheritedStyle的DataGridViewCell,的DataGridViewRow,DataGridViewColumn和派生類獲取全部的風格,包括從上級繼承樣式應用到當前單元格,行或列。
如上所述,獲得了一個樣式屬性的值會自動實例化一個新的DataGridViewCellStyle對象若是屬性還沒有之前設置。爲了不沒必要要地建立這些對象,行和列類有一個HasDefaultCellStyle屬性,您能夠檢查以肯定是否DefaultCellStyle屬性已設置。一樣,細胞類具備HasStyle屬性,指示是否Style屬性已設置。
每一個屬性的樣式上有一個相應的PropertyNameChanged DataGridView控件的事件。對於行,列和單元格屬性,事件名稱開頭「行」,「列」,或「細胞」(例如,RowDefaultCellStyleChanged)。這些事件發生時,每個對應的樣式屬性設置爲不一樣的DataGridViewCellStyle對象。這些事件不會發生當您檢索從樣式屬性的DataGridViewCellStyle對象,並修改其屬性值。爲了應對變化的單元格樣式對象自己,處理CellStyleContentChanged事件。
5.1.3樣式繼承
每一個DataGridViewCell的會從它的InheritedStyle屬性它的外觀。 DataGridViewCellStyle對象的此屬性返回繼承從類型DataGridViewCellStyle的屬性層次的價值。下面列出了這些屬性的順序在其中非頭細胞InheritedStyle獲取其值。
1。 DataGridViewCell.Style
2。 DataGridViewRow.DefaultCellStyle
3。 AlternatingRowsDefaultCellStyle(只適用於奇數行單元格指數)
4。 RowsDefaultCellStyle
5。 DataGridViewColumn.DefaultCellStyle
6。的DefaultCellStyle
對於行和列標題單元格,InheritedStyle屬性填充的值是從給定的順序在下面的列表源屬性。
1。 DataGridViewCell.Style
2。 ColumnHeadersDefaultCellStyle或RowHeadersDefaultCellStyle
3。的DefaultCellStyle
下圖演示了這個過程。
您還能夠經過特定的行和列繼承的樣式。列InheritedStyle財產繼承瞭如下屬性的值。
1。 DataGridViewColumn.DefaultCellStyle
2。的DefaultCellStyle
該行InheritedStyle財產繼承瞭如下屬性的值。
1。 DataGridViewRow.DefaultCellStyle
2。 AlternatingRowsDefaultCellStyle(只適用於奇數行單元格指數)
3。 RowsDefaultCellStyle
4。的DefaultCellStyle
對於每個由InheritedStyle屬性返回一個DataGridViewCellStyle對象屬性,屬性值是從第一個單元格樣式列表,在適當的相應的屬性設置爲除DataGridViewCellStyle類的默認值等。
下表說明了一個例子細胞ForeColor屬性的值是從包含列繼承。
類型DataGridViewCellStyle的範例前景色爲檢索對象的價值屬性
DataGridViewCell.Style Color.Empty
DataGridViewRow.DefaultCellStyle Color.Red
AlternatingRowsDefaultCellStyle Color.Empty
RowsDefaultCellStyle Color.Empty
DataGridViewColumn.DefaultCellStyle Color.DarkBlue
的DefaultCellStyle Color.Black
在這種狀況下,從單元格的行System.Drawing.Color.Red值是第一個在名單上的實際價值。這成爲該單元格的InheritedStyle ForeColor屬性值。
下圖說明了不一樣的DataGridViewCellStyle屬性能夠繼承他們的價值觀不一樣的地方。
經過利用樣式繼承的優點,能夠提供,而無需指定相同的信息在多個地方爲整個控制適當的樣式。
雖然標題單元格樣式繼承中所描述的身份參加,由DataGridView控件的ColumnHeadersDefaultCellStyle和RowHeadersDefaultCellStyle屬性返回的對象具備初始屬性值覆蓋由DefaultCellStyle屬性返回的對象的屬性值。若是你想由DefaultCellStyle屬性返回的對象設置爲適用於行和列標題的屬性,你必須設置由ColumnHeadersDefaultCellStyle和RowHeadersDefaultCellStyle屬性返回的DataGridViewCellStyle類爲默認顯示對象的相應屬性。
注:若是啓用視覺樣式,行和列標題(除TopLeftHeaderCell)會自動由當前的主題風格,覆蓋了這些屬性所指定的任何樣式。設置EnableHeadersVisualStyle屬性爲false,若是你想標題不使用XP的視覺樣式。
該DataGridViewButtonColumn,DataGridViewImageColumn和DataGridViewCheckBoxColumn類型還初始化由列DefaultCellStyle屬性返回的對象的一些值。有關詳細信息,請參見這些類型的參考文件。
5.1.4設置樣式動態
要自定義,特別值的單元格的樣式,實施一項CellFormatting事件的處理程序。此事件的處理程序收到的DataGridViewCellFormattingEventArgs類型的參數。此對象包含的屬性,讓您肯定單元格的值被格式化,其在DataGridView控制地沿。此對象還包含一個CellStyle屬性,初始化爲單元格的InheritedStyle屬性值被格式化。您能夠修改單元格樣式屬性來指定樣式的信息適合單元格的值和位置。
注:RowPrePaint和RowPostPaint事件還接收事件數據的DataGridViewCellStyle對象,但他們的案件,這是該行InheritedStyle屬性爲只讀目的副本,以及它的變動不會影響控制。
您還能夠動態改變以因應如CellMouseEnter和CellMouseLeave活動活動單個細胞的風格。例如,在爲CellMouseEnter事件處理程序中,你能夠存儲單元格的背景顏色(經過細胞的Style屬性檢索)的當前值,而後將其設置爲一個新的色彩,將突出顯示單元格時在它的鼠標懸停。在爲CellMouseLeave事件處理程序,而後就能夠恢復到原來的背景顏色值。
注:緩存在細胞的Style屬性中存儲的值是重要的,不管是否設置特定的樣式值。若是您暫時替換樣式設置,恢復到原來的「未設置」國家保障,細胞會返回從更高的層次繼承的樣式設置。若是您須要肯定在一個單元的實際效果風格的風格不管是繼承,使用單元格的InheritedStyle屬性。
5.2風俗畫
DataGridView控件提供了多個屬性,您能夠用它來調整外觀和基本行爲(外觀和感受)的單元格,行和列。若是您有要求,超越的DataGridViewCellStyle類的功能的時候,你能夠執行單元格或行的內容自定義繪製。單元格和行畫本身,你能夠處理各類如RowPrePaint的DataGridView,CellPainting和RowPostPaint繪畫活動。
5.2.1油漆件
自定義繪製的一個重要部分是油漆部件的概念。該DataGridViewPainParts枚舉用於指定哪些部分細胞油漆。枚舉值可結合在一塊兒,有一個單元不油漆塗料或特定部分。這裏是不一樣的部分:
PaintPart爲例前景色爲檢索對象的價值
全部的全部部件都畫
背景單元格的背景是畫使用單元格的背景顏色(1)
邊境的邊界是畫
ContentBackground單元格的內容是畫背景的一部分。 (2)
ContentForeground單元格的內容的前景部分是畫(2)
ErrorIcon錯誤圖標畫
重點增強對單元格焦點矩形畫
沒有任何部分是畫(1)
SelectionBackground畫的背景是,若是選中該單元格被選中。
註釋
1)若是一個單元格不繪製其背景則沒有什麼是畫。一個行或列執行任何做畫,確保至少細胞的背景畫,或者您執行您本身的自定義背景畫,不然仍然是無效的矩形(着色)。
2)每一個單元肯定什麼前景爲內容的背景和內容,以下面的列表描述的那樣塗料:
細胞類型的內容前景內容背景
文本框單元格的文字是畫沒有畫
扣式電池文字畫,畫按鈕
組合框單元格的文字是畫,畫組合框
選中複選框是畫沒有畫
連接單元格文本連接是沒有畫成畫
圖像細胞圖像是畫沒有畫
標題欄標題欄文字排序雕畫
行頭行頭文字Current行三角形,編輯鉛筆和新行的指標是畫
5.2.2行預油漆塗料和郵政業
您能夠經過處理一個或DataGridView.RowPrePaint和DataGridView.RowPostPaint兩個事件的DataGridView行的外觀。這些活動的設計,讓你能夠畫只有你想在DataGridView控制,而讓其他的油漆。例如,若是你想畫一個自定義的背景,你能夠處理DataGridView.RowPrePaint事件,並讓本身的單個細胞塗料前景的內容。在RowPrePaint事件你能夠設置PaintParts事件參數屬性來輕鬆定製的細胞如何油漆。例如,若是您想保留的任何選擇,或從繪畫的焦點細胞,你RowPrePaint事件將設置像這樣PaintParts屬性:
e.PaintParts = DataGridViewPaintParts.All&
〜(DataGridViewPaintParts.Focus |
DataGridViewPaintParts.SelectionBackground);
這也能夠寫成:
e.PaintParts =(DataGridViewPaintParts.Background |
DataGridViewPaintParts.Border |
DataGridViewPaintParts.ContentBackground |
DataGridViewPaintParts.ContentForeground |
DataGridViewPaintParts.ErrorIcon);
或者,也可讓本身和油漆的細胞中添加一個自定義事件處理程序的DataGridView.RowPostPaint前景的內容。您還能夠禁用油漆和塗料的一切細胞在DataGridView.RowPrePaint本身的事件處理程序
5.3 Autosizing
DataGridView控件提供了自定義的列和行的調整大小行爲的許多選項。一般狀況下,DataGridView單元格不調整的基礎上的內容。相反,她們還會給任何顯示值比電池大。若是內容能夠做爲一個字符串顯示,該單元格顯示在工具提示。
默認狀況下,用戶能夠用鼠標拖動來顯示更多信息行,列和標題分隔。用戶還能夠雙擊一個分頻器來自動調整相關的行,列或標題帶其內容爲基礎。列共享默認狀況下,控制可用寬度,因此,若是用戶能夠調整控制,例如,若是它是一個可調整大小的對接形式,他們也能夠更改列的全部可用的展現空間。
DataGridView控件提供的屬性,方法和事件,使您能夠自定義或禁用這些用戶導向的全部行爲。此外,您能夠經過編程方式調整行,列和標題,以適合他們的內容,也能夠將其配置爲自動調整本身只要其內容的變化。
常見問題:
1)如何調整最後一列的寬度使其佔據網格的剩餘客戶區?
5.3.1在Windows窗體DataGridView控件調整大小選項
DataGridView行,列和標題能夠改變許多不一樣的事件結果的大小。下表顯示了這些事件。
發生說明
用戶調整大小用戶能夠經過拖動或雙擊行,列或標題分隔大小的調整。
控制調整在列填充模式,列寬度變化時,控制寬度的改變,例如,當控件停靠到其父形式和用戶調整的表格。
細胞在基於內容的自動調整大小模式值的變化,大小變化,以適應新的顯示值。
方法調用的方案內容爲基礎的大小可讓用戶調整大小的基礎上乘機在方法調用時單元格值。
屬性設置也能夠設置特定的高度和寬度值。
默認狀況下,啓用用戶調整大小,自動調整大小被禁用,是更普遍的單元格值比列剪裁。
下表顯示的狀況,你能夠用它來調整預設的行爲,或使用特定的調整大小選項來達到特定的效果。
方案實施
使用列填充顯示一樣,在一列,佔據了整個寬度的控制數量相對較少,而不顯示水平滾動條大小的數據模式。 AutoSizeColumnsMode屬性設置爲Fill。
使用列填充不一樣大小顯示值模式。 AutoSizeColumnsMode屬性設置爲Fill。初始化設置列的FillWeight屬性或調用控件AutoResizeColumns灌裝後用數據控制方法相對列寬度。
使用列填充不一樣的重要性與價值模式。 AutoSizeColumnsMode屬性設置爲Fill。設置大量列的MinimumWidth值,必須始終顯示的數據部分或使用一個尺寸的選擇之外填補特定列模式。
使用列填充模式,以免顯示控件的背景。設置最後一列AutoSizeMode屬性爲Fill和使用其餘尺寸的其餘列選項。
顯示一個固定寬度的列,如圖標或ID列。 AutoSizeMode設置爲None,可調整大小爲False的列。初始化設置width屬性,或者調用控件AutoResizeColumn後用數據填充它的寬度控制方法。
大小時自動調整單元格內容的變化,以免裁減和優化使用空間。設置一個自動調整大小屬性的值,表示一個基於內容的大小調整模式。爲了不性能降低時,大量的數據工做,使用一個尺寸模式,只計算顯示的行。
調整大小以適應顯示的行值,以免性能降低時,許多行工做。使用自動或編程調整大小適當的調整大小模式枚舉值。要調整大小,以適應在新顯示的行滾動時,請在一個滾動的事件處理程序大小的方法價值。定製用戶雙擊調整大小,以便顯示的行的值只有在肯定新的尺寸,要求在一個RowDividerDoubleClick或ColumnDividerDoubleClick事件處理程序大小的方法。
只有在特定時間調整大小以適應單元格內容,以免性能罰款或啓用用戶調整大小。調用事件處理程序中的基於內容的大小的方法。例如,使用DataBindingComplete事件綁定後初始化大小和處理CellValidated或CellValueChanged事件調整大小,以彌補用戶編輯或綁定的數據源的變化。
調整多行單元格內容的行高。確保該列的寬度是用於顯示相應的文本段落並使用自動或編程的基於內容的行大小來調整高度。另外,還要確保與細胞顯示多內容使用的WrapMode細胞式的真實價值。
一般,你會使用自動調整大小模式,以維持列列寬或將其設置爲特定寬度前行高進行調整。
5.3.2用鼠標調整大小
默認狀況下,用戶能夠調整行,列和標題不使用自動大小調整模式對細胞價值觀爲基礎。爲了防止其餘模式,例如列填充模式,縮放用戶設置一個或如下的DataGridView屬性:
•AllowUserToResizeColumns
•AllowUserToResizeRows
•ColumnHeadersHeightSizeMode
•RowHeadersWidthSizeMode
您還能夠防止大小設置其Resizable屬性由單個行或列的用戶。默認狀況下,Resizable屬性值是基於對列AllowUserToResizeColumns屬性值和屬性值的行AllowUserToResizeRows。若是你明確地設置大小可調整爲True或False,可是,指定的值控制值覆蓋該行或列中。設置調整大小to NotSet恢復繼承。
因爲NotSet還原值繼承,Resizable屬性永遠不會返回NotSet值,除非該行或列並無被添加到一個DataGridView控制。若是您須要肯定是否行或列Resizable屬性值繼承,審查其國家的財產。若是該國值包括ResizableSet標誌,Resizable屬性值不繼承。
5.3.3自動調整大小
有兩種自動調整大小在DataGridView控制類型:列填充模式和基於內容的自動調整大小。
列填充模式致使在控件中可見列,以填補該控件的顯示區域的寬度。如需這個模式的詳細信息,請參閱列填充模式一節。
您還能夠配置行,列和標題的大小自動調整以適應其單元格內容。在這種狀況下,大小調整單元格內容時發生變化。
注意:若是你保持在自定義數據緩存單元格的值使用虛擬模式,自動調整大小時發生用戶編輯單元格值,但不會發生改變時,外面的一CellValuePushed事件處理緩存值。在這種狀況下,調用UpdateCellValue方法強制控制更新單元格的顯示和應用當前的自動調整大小模式。
若是基於內容的自動調整大小僅用於也就是說,對於行,但不列,或列,但不是行和的WrapMode還啓用一維啓用,大小調整時,也會發生在其餘方面的變化。例如,若是行,但不列自動調整大小和配置的WrapMode已啓用,用戶能夠拖動列分隔來改變一個列和行高將自動調整使細胞內容仍然充分顯示寬度。
若是配置基於內容的自動調整大小行和列和的WrapMode啓用,DataGridView控件將調整單元格內容改變大小時,將使用一個理想的細胞高度對寬度的比例,當計算新的大小。
要配置標題和行和列不會覆蓋控制值,漿紗模式設置一個或多個如下的DataGridView屬性:
•ColumnHeadersHeightSizeMode
•RowHeadersWidthSizeMode
•AutoSizeColumnsMode
•AutoSizeRowsMode
若要重寫控件的列大小的單個列模式,將其AutoSizeMode屬性的值比NotSet等。一列大小調整模式其實是取決於它的InheritedAutoSizeMode財產。這個屬性的值是基於列的AutoSizeMode屬性值,除非該值是NotSet,在這種狀況下控制的AutoSizeColumnsMode值繼承。
請謹慎使用基於內容的自動調整大小時,大量數據的工做。爲了不性能降低,使用自動調整大小模式,而不是分析計算中的每一行控制的基礎上所顯示的行惟一的大小。爲得到最佳性能,使用編程調整大小,而不是讓你在特定的時間能夠調整,如新的數據後當即加載。
基於內容的自動調整大小模式不會影響行,列或標題,你已經經過設置行或列的Visible屬性或控制RowHeadersVisible或ColumnHeadersVisible屬性爲false隱藏。例如,若是列是隱藏後,它會自動調整以適應一個大單元格的值,隱藏的列將不會改變它的大小,若是大所在的行單元格的值將被刪除。自動調整大小時,不會出現能見度的變化,所以更改列的Visible屬性返回true,將不會強迫它從新計算其大小的當前內容爲基礎。
方案內容爲基礎的大小影響的行,列和標題不論其知名度。
5.3.4編程調整大小
禁用自動調整大小時,您能夠經過編程設置精確的寬度經過下列屬性或行,列或標題的高度:
•RowHeadersWidth
•ColumnHeadersHeight
•DataGridViewRow.Height
•DataGridViewColumn.Width
您還能夠經過編程調整行,列和標題,以適合他們的內容使用下列方法:
•AutoResizeColumn
•AutoResizeColumns
•AutoResizeColumnHeadersHeight
•AutoResizeRow
•AutoResizeRows
•AutoResizeRowHeadersWidth
這些方法將調整行,列或標題一次,而不是連續的大小配置它們。新的大小自動計算顯示沒有剪輯的全部單元格內容。當您以編程方式調整列有填充InheritedAutoSizeMode屬性值,可是,計算出的基於內容的寬度按比例用於調整列FillWeight屬性值,實際列寬,而後根據這些新的計算比例,讓全部列填充該控件的可用顯示區域。
編程調整大小能夠有效避免連續調整大小的性能損失。它也爲用戶提供有用的調整大小的行,列和標題的初始大小,列填充模式。
你一般會在特定時間調用的方案調整方法。例如,您可能編程加載數據後,當即調整全部列,或者你可能一個特定的編程方式調整後的行某單元格值已被修改。
5.3.5自定義基於內容的調整大小行爲
您能夠自定義大小的行爲時,派生的DataGridView單元格,行和列類型的工做經過覆蓋DataGridViewCell.GetPreferredSize(),DataGridViewRow.GetPreferredHeight(),或DataGridViewColumn.GetPreferredWidth()方法或經過調用DataGridView的保護,在派生大小的方法重載控制。受保護的大小的方法重載的目的是在對工做,以實現理想的單元格高度與寬度的比例,避免過於寬或高的細胞。例如,若是調用AutoResizeRows(DataGridViewAutoSizeRowsMode,布爾)的AutoResizeRows方法重載並傳入一個虛假的布爾參數的值,過載將計算在該行細胞的理想的高度和寬度,但它會調整行高而已。而後,您必須調用AutoResizeColumns方法來調整列寬度以計算的理想選擇。
5.3.6基於內容的調整大小選項
由大小屬性和方法使用的枚舉有基於內容的大小類似的價值觀。有了這些值,你能夠限制哪些細胞是用來計算首選大小。對於全部大小枚舉,其名稱是指顯示的單元格的值限制在他們的計算顯示的行的單元格。不包括行是有用的,以免性能損失,當您使用的是大量的行工做。您還能夠限制的計算,以在頁眉或nonheader細胞的細胞值。
5.4選擇模式
DataGridView控件提供了一系列用於配置用戶如何選擇單元格,行和列的多種選擇你。例如,您能夠啓用單一或多重選擇,全行或列的選擇,當用戶單擊單元格,行或整列選擇或僅當用戶點擊他們的標題,也使小區選擇。若是您要提供您的選擇本身的用戶界面,您能夠禁用普通的選擇和處理全部的編程選擇。此外,還可讓用戶選定的值複製到剪貼板。
有時候你但願你的應用程序來執行的DataGridView控制範圍內用戶的選擇爲基礎的行動。根據不一樣的操做,您可能但願限制的種類的選擇都是可能的。例如,假設你的應用程序能夠打印出當前選中的記錄報告。在這種狀況下,您可能須要配置的DataGridView控件,以便在連續點擊任何地方老是選擇整行,因此這隻能有一個時間行能夠被選中。
您能夠經過設置SelectionMode屬性爲下列DataGridViewSelectionMode枚舉值之一容許的選擇。
DataGridViewSelectionMode值描述
CellSelect單擊單元格以選中它,行列標題不能用於選擇。
ColumnHeaderSelect單擊單元格以選中它,單擊列標題選中整列。此時列標題不能用於排序。
FullColumnSelect單擊單元格或列標題會選中它們所在的列,此時列標題不能用於排序。
FullRowSelect單擊單元格或行標題會選中它們所在的行。
RowHeaderSelect DGV的默認選擇模式,單擊單元格選中該單元格,單擊行標題則選中整行。
注意:在運行時改變選擇模式會自動清除當前選擇的內容。
默認狀況下,用戶能夠選擇用鼠標拖動,按Ctrl或Shift的同時選擇延長或修改的選擇,或者點擊左上角的標題單元格來選擇控件中的全部細胞的多個行,列或單元格。爲了防止這種行爲,設置爲false MultiSelect屬性。
該FullRowSelect和RowHeaderSelect模式容許用戶經過選擇刪除,再按DELETE鍵的行。用戶能夠刪除行,只有在當前單元格不處於編輯模式,AllowUserToDeleteRows屬性設置爲true,而且基礎數據源支持用戶驅動的行刪除。請注意,這些設置不會防止綱領性行刪除。
5.4.1編程選擇
目前的選擇模式限制了方案選擇,以及用戶的選擇行爲。你能夠改變當前選擇編程方式設置的任何單元格,行或列在DataGridView控制選錄的財產。您還能夠選擇經過SelectAll方法控制全部單元格,選擇模式而定。要清除的選擇,使用ClearSelection方法。
若是MultiSelect屬性設置爲true,則能夠添加或刪除DataGridView元素從選擇經過改變這些元素的Selected屬性。不然,設置一個元素的Selected屬性爲true自動刪除從選擇的其餘因素。
注意:改變CurrentCell屬性的值不會改變當前選擇的內容。
經過SelectedCells,SelectedRows和的SelectedColumns屬性你能夠訪問當前選中的單元格,行和列。不過當全部單元格都被選中的時候,使用這些屬性效率會比較低,爲此可首先使用AreAllCellsSelected方法查看是否已選中所有單元格。此外,訪問這些屬性來查看選中單元格,行和列的數目效率也比較低,此時應該使用GetCellCount,GetRowCount和GetColumnCount方法,傳給它們的參數爲DataGridViewElementStates.Selected。
5.5滾動(滾動)
DataGridView中毫無疑問地會提供對水平和垂直滾動條的支持,它同時也支持使用鼠標滾輪進行垂直滾動。水平方向的滾動基於像素值,而垂直方向的滾動則基於行的索引,不支持垂直的DataGridView方向的基於像素值的滾動。
5.5.1 Scroll事件
當你滾動DataGridView的引起Scroll事件,讓您被通知滾動發生。對滾動事件參數定位屬性可讓你知道滾動的方向。
5.5.2滾動條
DataGridView的滾動條能夠訪問,它經過保護HorizontalScrollBar和VerticalScrollBar屬性顯示。 ScrollBar控件直接訪問這些讓你擁有滾動更好的控制。
5.5.3滾動屬性
有許多的屬性,提供更大的詳細程度如何設置DataGridView的滾動。該圖突出這些屬性和在這種狀態下它們的值。這些屬性的讀/寫除了FirstDisplayedScrollingColumnHiddenWidth和VerticalScrollingOffset屬性。
5.6排序
默認狀況下,用戶能夠按一下文字方塊的欄標題在DataGridView控件中的數據。您能夠修改特定列SortMode屬性,容許用戶經過其餘列類型進行排序時,這樣作是有道理的。您還能夠經過編程對數據進行排序任何列或多個列。
DataGridView列有三種排序模式。每一個列的排序模式是經過指定的列,它能夠設置爲如下DataGridViewColumnSortMode枚舉值之一SortMode屬性。
DataGridViewColumnSortMode值描述
自動默認爲文本框列。除非列標頭用於選擇,單擊列標題此列自動排序,並顯示一個指示排序順序字形的DataGridView。
NotSortable默認非文本框列。您能夠按該列編程,可是,它不適合排序,因此沒有空間爲排序標誌符號保留。
編程您能夠按該列編程和空間是爲排序標誌符號保留。
您可能要更改的列,默認爲NotSortable若是它包含能夠有意義有序值的排序方式。例如,若是你有一個數據庫列包含表示項狀態的數字,你能夠顯示一個圖像列綁定到數據庫列的這些數字對應的圖標。而後,您能夠改變一個CellFormatting事件處理程序將圖像顯示值的數值單元格值。在這種狀況下,設置SortMode屬性,使您的用戶自動排序列。自動分揀將使您的用戶組項目,具備相同的狀態,即便各國所對應的數字沒有一個天然順序。複選框列是另外一個例子,自動排序分組,在同一國家的項目有用。
你能夠在任何編程方式進行排序列中的值或多個列的DataGridView,不管SortMode設置。編程排序是有用的當您想爲排序或當你想實現本身的自定義排序用戶界面(UI)。提供本身的排序用戶界面是有用的,例如,當您設置了DataGridView選擇模式,使列標題選擇。在這種狀況下,雖然列標頭不能用於排序,你仍然想的標題來顯示相應的排序標誌符號,因此你會設置SortMode屬性編程。
列設置爲編程排序模式不會自動顯示排序標誌符號。對於這些列,你必須顯示的字形經過設置DataGridViewColumnHeaderCell.SortGlyphDirection本身的財產。這是必要的,若是你想在自定義排序的靈活性。例如,若是按多列DataGridView的,你可能要顯示多個排序標誌符號或無排序標誌符號。
雖然您能夠經過編程任意列進行排序的DataGridView,一些欄目,如按鈕列,可能不包含能夠有意義的有序值。對於這些列,一個NotSortable SortMode屬性設置表示,它將永遠不會被用於排序的,因此沒有必要儲備爲排序標誌符號頭空間。
當DataGridView的排序,你能夠同時肯定排序列和經過檢查SortedColumn和SortOrder的屬性的值進行排序。這些值不是一個自定義排序操做後,有意義的。有關自定義排序信息,請參見本主題中的自定義排序節後面。
當DataGridView控件同時包含綁定和未綁定列進行排序,在未綁定列的值不能自動維護。爲了保持這些值,你必須執行VirtualMode屬性設置爲true,並處理CellValueNeeded和CellValuePushed事件虛擬模式。
5.6.1編程排序
您能夠排序的DataGridView編程方式調用它的排序方法。
本的Sort(DataGridViewColumn,ListSortDirection)Sort方法重載採用DataGridViewColumn和一個枚舉值做爲參數ListSortDirection。此重載時很是有用,能夠經過與有意義的命令,但你不想配置值的列自動分揀排序。當調用此重載並同一個DataGridViewColumnSortMode.Automatic的SortedColumn和SortOrder的性能SortMode屬性值列經過自動設置和相應的排序標誌符號出如今列標題。
注意:當DataGridView控件綁定經過設置DataSource屬性到外部數據源,的Sort(DataGridViewColumn,ListSortDirection)方法重載不能用於未綁定列。此外,當VirtualMode屬性爲true,則能夠只綁定列調用此重載。要肯定是否列是數據綁定,檢查IsDataBound屬性值。在綁定模式下未綁定列排序不受支持。
5.6.2自定義排序
您能夠經過使用自定義的Sort(IComparer)Sort方法重載或經過處理DataGridView的SortCompare事件。
的Sort(IComparer)方法重載採用一個實現類做爲參數的IComparer接口的實例。此重載頗有用,當您要提供自定義排序,例如,當在一列中的值沒有天然排序順序或者當天然排序順序是不適當的。在這種狀況下,您不能使用自動排序,但您可能仍然但願用戶經過點擊排序列標題。你還能夠打電話爲ColumnHeaderMouseClick此重載事件處理程序,若是你不使用選擇欄標題。
注意:的Sort(IComparer)方法重載僅當DataGridView控件未綁定到外部數據源和VirtualMode屬性值爲false。要自定義綁定到外部數據源的列排序,你必須使用排序的數據源提供的操做。在虛擬模式下,你必須爲本身的未綁定列排序操做。
要使用的Sort(IComparer)方法重載,您必須建立本身的類實現IComparer接口。此接口要求您的類來實現IComparer.Compare(Object)方法,對此,做爲輸入傳遞時的DataGridView的Sort(IComparer)方法重載被稱爲DataGridViewRow對象。有了這個,你能夠計算出正確的行排序的基礎上在任一列的值。
的Sort(IComparer)方法重載不設置SortedColumn和SortOrder的屬性,因此你必須老是設置DataGridViewColumnHeaderCell.SortGlyphDirection屬性以顯示排序標誌符號。
做爲對的Sort(IComparer)方法重載替代方法,能夠經過實施提供了SortCompare事件處理程序自定義排序。此事件發生在用戶單擊列或配置自動分揀頭當調用Sort方法的Sort(DataGridViewColumn,ListSortDirection)重載。事件發生時,每行一對在控制,使您可以計算它們的正確順序。
注:SortCompare事件不會發生當DataSource屬性設置或當VirtualMode屬性值爲true。
5.6.3常見問題及案例
1)如何避免用戶對列排序?
2)如何針對多個列排序?
5.7邊框樣式
使用DataGridView控件,您能夠自定義該控件的邊框和網格線,以改善用戶體驗的外觀。您能夠修改除了爲細胞內控制邊境網格線的顏色和樣式的控件的邊框樣式。網格線顏色控制,經過GridColor財產。您還能夠申請普通細胞,行標題單元格和列標題單元格不一樣的單元格邊框樣式。對於先進的邊框樣式的DataGridView提供先進的邊框樣式的屬性。
注:網格線顏色僅用於與DataGridViewCellBorderStyle枚舉和枚舉的DataGridViewHeaderBorderStyle單值單,SingleHorizontal和SingleVertical值。這些枚舉的其餘值使用由操做系統指定的顏色。此外,當視覺樣式的Windows XP及以上的啓用,GridColor屬性值不被使用。
5.7.1標準邊框樣式
邊框樣式控制標準經過CellBorderStyle,RowHeadersBorderStyle和ColumnHeadersBorderStyle屬性。
下表列出了標準經過所提供的邊框樣式:
邊框值描述
Fixed3D一個三維邊框。
FixedSingle單行邊框。
無無邊框。
5.7.2高級邊境風格
DataGridView控件容許你徹底自定義其外觀,包括細胞和頭的邊界。 DataGridView的有CellBorderStyle,ColumnHeadersBorderStyle和RowHeadersBorderStyle屬性,讓您設置單元格邊框的外觀。可是,若是您須要進一步定製邊界,DataGridViewAdvancedBorderStyle類容許您設置單元格的我的雙方的邊框樣式。對DataGridViewAdvancedBorderStyle左,右,頂部和底部屬性表明左,右,上,一個細胞和底部邊框,分別爲。您能夠設置在AdvancedCellBorderStyle,AdvancedColumnHeadersBorderStyle,AdvancedRowHeadersBorderStyle DataGridView的屬性這些屬性產生的細胞之間的邊界,展示多種風采。
下表列出了可用的先進的邊框樣式,能夠設置爲左,右,頂部和底部部分。請注意,某些組合是無效的。
邊框值描述
嵌入一個三維邊框。
InsetDouble單行邊框。
無無邊框。
NotSet邊界是沒有設置
一開始就是單行凸起邊框
OutsetDouble一個雙線凸起邊框
OutsetPartial單行邊界包含凸起部分
單單行邊界
5.8輸入,編輯模式
默認狀況下,用戶能夠經過在編輯,或按F2鍵當前DataGridView的文本框格的內容。這使得在編輯模式下,若是下列條件所有獲得知足手機:
•基礎數據源支持編輯。
•DataGridView控件已啓用。
•將EditMode屬性值不是EditProgrammatically。
•單元格,行,列的ReadOnly屬性和控制,都設置爲false。
在編輯模式下,用戶能夠更改單元格的值,而後按Enter鍵提交更改或ESC細胞恢復到其原始值。
您能夠配置一個DataGridView控件,以使單元格進入編輯模式,一旦它成爲當前單元格。該ENTER鍵和ESC鍵的行爲在這種狀況下保持不變,但細胞仍然處於編輯模式後,該值被提交或還原。您還能夠配置控制,使細胞進入編輯模式僅當用戶鍵入單元格或只有當用戶按下F2鍵。最後,您能夠阻止其進入編輯,除非你調用BeginEdit方法模式細胞。
下表描述了不一樣的編輯模式可供選擇:
編輯模式值描述
EditOnEnter編輯開始時,細胞接收焦點。這種模式是有用的當按下TAB鍵,進入跨越行值,或當按下回車鍵,進入下一個列值。
EditOnF2編輯開始時按下F2鍵時,單元格具備焦點。此模式放置在單元格內容的末尾的選擇點。
開始編輯EditOnKeystroke當任何字母數字鍵被按下,而細胞具備焦點。
EditOnKeystrokeOrF2編輯開始時,任何字母數字鍵或F2鍵被按下,而細胞具備焦點。
EditProgrammatically編輯時,纔開始BeginEdit方法被調用。
5.9剪貼板拷貝模式
當你使細胞複製,你才能在DataGridView控件的數據很容易接觸到其餘應用程序經過剪貼板。 DataGridView控件複製到選定的單元格的每一個剪貼板的文本表示。此值是單元格的值轉換爲圖像細胞,Description屬性的值的字符串或。其內容後加入爲製表符分隔的文本值的剪貼簿在諸如記事本和Excel應用程序粘貼,並做爲應用程序,如Word粘貼到HTML格式的表格。
您能夠配置單元格值複製到複製只,包括在剪貼板上的數據行和列標題文本,或包含標題文本僅當用戶選擇整個行或列。
下表列出了不一樣的剪貼板複製模式:
剪貼板拷貝模式說明
禁用複製到剪貼板被禁用。
EnableAlwaysIncludeHeaderText所選單元格的文本值能夠被複制到剪貼板。標題文字是否列入行和包含選定單元格的列。
EnableWithAutoHeaderText所選單元格的文本值能夠被複制到剪貼板。行或列標題的文本包含或包含的行只選擇當SelectionMode屬性設置爲RowHeaderSelect或ColumnHeaderSelect和至少一個頭被選中單元格的列。
EnableWithoutHeaderText所選單元格的文本值能夠被複制到剪貼板。標題文字是否不包括在內。
在選擇模式的不一樣,用戶能夠選擇多個不連續的細胞羣。當用戶複製到剪貼板細胞,行和列,沒有選定的單元格不會被複制。全部其餘行或列成爲複製到剪貼板上的數據表的行和列。在這些行或列未選定的單元格被複制到剪貼板做爲空白佔位符。
當用戶複製內容時,DataGridView控件添加到剪貼板DataObject中。此數據對象是取自GetClipboardContent()方法。你能夠調用這個方法時,您但願以編程方式將數據添加對象到剪貼板。該GetClipboardContent()方法經過調用DataGridViewCell.GetClipboardContent檢索()方法爲個別單元格的值。你能夠重寫派生類中任一這些方法或兩個自定義複製的單元格的佈局,或支持格式的其餘數據。
5.10凍結的列/行
當用戶查看數據有時他們須要參考一列或列集頻繁。例如,當顯示的客戶信息表,其中包含許多列,顯示是很是有用的在任什麼時候候,客戶名稱,同時使其餘列可見區域以外的滾動。
爲了實現這一行爲,您能夠凍結在控制列。這是經過設置在列或行凍結的財產。當你凍結一列,全部列在它的左邊(或在從右到左的語言腳本右),凍結。凍結列留在原地,而全部其餘列能夠滾動。行以相似的方式行事:前行中的全部行被凍結的凍結,以及維持不變,而在非冰凍行能夠滾動。
5.11實現自定義和編輯控制細胞/細胞
您能夠實如今你的派生類來建立一個細胞的細胞類型具備編輯功能,但不承載的編輯模式控制IDataGridViewEditingCell接口。要建立一個控件,你能夠在一個宿主細胞中的編輯模式,能夠實現從Control派生的類IDataGridViewEditingControl接口。
5.11.1 IDataGridViewEditingControl
支持先進的單元格編輯功能一般使用一個託管控件是從Windows窗體控件派生的。此接口由編輯控件,如DataGridViewComboBoxEditingControl和DataGridViewTextBoxEditingControl,這是由相應的DataGridView單元格,如的DataGridViewComboBoxCell和DataGridViewTextBoxCell,當他們處於編輯模式主持。
單元格能夠承載編輯控件設置其EditType屬性類型,表示一個類型的編輯控件的類型。
5.11.2 IDataGridViewEditingCell
此接口的類沒有提供存取指定的編輯控制值的用戶界面(UI)。在這種狀況下用戶界面顯示不管是在細胞處於編輯模式。該DataGridViewCheckBoxCell的是一個細胞,它實現了IDataGridViewEditingCell接口的例子。
其餘細胞類型,如的DataGridViewButtonCell,提供一個用戶界面,但不存儲用戶指定的值。在這種狀況下,細胞類型不落實IDataGridViewEditingCell或主機一個編輯控制。
5.12虛擬模式
使用虛擬模式,您能夠管理之間的DataGridView控件和自定義數據緩存交互。爲了實現虛擬模式,設置VirtualMode屬性爲true,並處理一個或本主題描述的事件更多。您一般處理至少CellValueNeeded事件,它使控件的外觀在數據緩存值。
5.12.1綁定模式和虛擬模式
虛擬模式只有當你須要補充或替換綁定模式。在綁定模式下,能夠設置DataSource屬性和控制自動加載從指定的源數據和提交給它的用戶更改回來。您能夠控制哪些綁定列的顯示方式,和通常的數據源自己處理,如排序操做。
5.12.2補充綁定模式
您能夠經過顯示補充隨着綁定列綁定列綁定模式。這有時也被稱爲「混合模式」,是用來顯示像計算值或用戶界面(UI)控制的東西有用。
因爲未綁定列以外的數據源,他們是忽視了數據源的排序操做。所以,當您在混合模式下啓用排序,你必須管理一個本地緩存中綁定數據,並實現虛擬模式,讓DataGridView控件交互。
5.12.3常見問題及案例
1)如何顯示綁定的數據綁定以及數據?
2)我怎樣的數據顯示,從兩個表來?
5.12.4更換綁定模式
若是綁定模式沒法知足您的性能需求,您能夠經過虛擬管理模式的自定義事件處理程序緩存中的全部數據。例如,你可使用虛擬模式來實現一個公正的實時數據加載的機制,只是從一個網絡數據庫,得到最佳性能所必需的數據檢索。這種狀況是很是有用的大量時,經過速度較慢的網絡鏈接或與客戶機的數據有一個內存或存儲空間有限的工做。
5.12.5虛擬模式事件
若是您的數據是隻讀的,CellValueNeeded事件多是惟一的事件,你將須要處理。額外的虛擬模式事件讓你啓用特定的功能,如用戶編輯,添加和刪除行和行級的交易。
一些標準的DataGridView事件(如發生的事件當用戶添加或刪除行,或在編輯單元格值時,解析,驗證,或者格式化)在虛擬模式中很是有用,以及。你也能夠處理事件,讓你保持在一個一般不綁定的數據源中存儲的值,如細胞提示文本,單元格和行的錯誤文本,單元格和行的快捷菜單數據,和行高的數據。
下列事件發生時,才VirtualMode屬性設置爲true。
事件描述
CellValueNeeded由控制用於檢索從顯示數據高速緩存單元格的值。此事件只發生在未綁定列細胞。
CellValuePushed由控制用於提交,能夠向用戶輸入的數據高速緩存單元。此事件只發生在未綁定列細胞。
調用方法時UpdateCellValue更改以外的CellValuePushed事件處理緩存值,以確保當前值顯示在控件中的做用,並適用於目前全部自動調整大小模式。
NewRowNeeded由控件用來指示一個數據高速緩存中的新行的須要。
RowDirtyStateNeeded的控制,用來肯定行是否有任何未提交的更改。
CancelRowEdit使用的控制,代表該行應恢復其緩存的值。
如下事件在虛擬模式中很是有用,但也可使用了VirtualMode屬性設置無關。
事件的說明
UserDeletingRow
UserDeletedRow
RowsRemoved
RowsAdded由控件用來指示行被刪除或添加,讓您更新相應的數據高速緩存。
CellFormatting
CellParsing
CellValidating
CellValidated
RowValidating
RowValidated使用的顯示格式爲單元格值和解析和驗證用戶輸入控制。
CellToolTipTextNeeded由控制單元用於檢索工具提示文本當DataSource屬性設置或VirtualMode屬性爲true。
工具提示顯示細胞只有在ShowCellToolTips屬性值爲true。
CellErrorTextNeeded
RowErrorTextNeeded的控制,用來檢索單元格或行的錯誤文本當DataSource屬性設置或VirtualMode屬性爲true。
調用方法或UpdateRowErrorText UpdateCellErrorText方法,當你更改單元格或行的錯誤文本,以確保當前值在控件中顯示。
細胞與行的錯誤標誌符號時顯示ShowCellErrors和ShowRowErrors屬性值是正確的。
CellContextMenuStripNeeded
RowContextMenuStripNeeded由控制用於檢索單元格或行的ContextMenuStrip當控件的DataSource屬性設置或VirtualMode屬性爲true。
RowHeightInfoNeeded
RowHeightInfoPushed由控制用於檢索或存儲數據的高速緩存行中高度信息。調用方法時改變UpdateRowHeightInfo緩存行以外的RowHeightInfoPushed事件處理的高度信息,以確保當前值在控制顯示器使用。
5.12.6在虛擬模式下的最佳實踐
若是要實現虛擬模式,以工做效率的大量數據,你也想確保您正在使用DataGridView控件自己的效率。請參閱下面的最佳作法的信息
5.13容量(容量)
通常來講,在DataGridView沒有硬編碼容量限制。網格的設計,使愈來愈多的內容能夠添加的機器變得更快,並有更多的內存。儘管如此,格並非用來處理大量列。若是您添加超過300行,您會開始注意到在隨着咱們對電網的表現卻不是這樣的優化性能的退化。若是你須要一個大量的列格,而後在DataGridView可能不符合您的需求。關於支持的行數時,DataGridView是受內存限制。當使用虛擬模式,您能夠輕鬆支持超過200萬行。看看你能夠作的事情(不要作),以提升內存的使用狀況和性能的最佳作法的信息,下面一節。
6個最佳實踐(最佳作法)
DataGridView控件的設計提供最大的可擴展性。若是你須要顯示大量數據,你應該按照本主題中所述,以免內存或有辱人格的用戶界面(UI)的響應消耗大量的指導方針。
6.1使用高效單元格樣式
每一個單元格,行和列能夠有本身的樣式信息。樣式信息存儲在DataGridViewCellStyle對象。創造許多我的DataGridView元素單元格樣式的對象能夠是低效的,特別是當大量數據的工做。爲了不性能的影響,請遵循下列準則:
•避免爲單個DataGridViewCell或DataGridViewRow對象的單元格樣式屬性。這包括由RowTemplate行對象屬性中指定。每一個新行是從行模板克隆將接收其模板的單元格樣式對象的副本。爲了得到最大的可擴展性,設置在DataGridView的單元格樣式屬性的水平。例如,設置DefaultCellStyle屬性,而不是DataGridViewCell.Style財產。
•若是某些細胞須要的格式之外的默認格式,在使用相同的單元格,行或列組的DataGridViewCellStyle實例。避免直接設置個別類型的單元格,行和列DataGridViewCellStyle屬性。對於一個單元格樣式共享的例子,請參見如何:設置單元格樣式的默認爲Windows窗體DataGridView控件。您也可避免性能降低時,經過處理CellFormatting設置事件處理個別單元格樣式。有關示例,請參見如何:自定義的數據格式在Windows窗體DataGridView控件。
•當肯定一個單元格樣式,使用DataGridViewCell.InheritedStyle財產,而不是DataGridViewCell.Style財產。訪問Style屬性建立一個DataGridViewCellStyle類的新實例若是該屬性尚未被使用。此外,這個對象可能不包含完整的樣式爲單元格的信息,若是有些樣式從行,列或控件繼承。欲瞭解更多有關單元格樣式繼承的詳細信息,請參閱細胞在Windows窗體DataGridView控件樣式。
6.2使用高效快捷菜單
每一個單元格,行和列能夠有它本身的快捷菜單。在DataGridView控制快捷菜單ContextMenuStrip控件表明。這正好與單元格樣式對象做爲,創造許多我的DataGridView元素的快捷菜單將產生負面影響性能。爲了不這種損失,請使用下列準則:
•避免爲單個單元格和行的快捷菜單。這包括行模板,這是克隆了它的快捷方式菜單時,新行被添加到控件一塊兒。爲了得到最大的可擴展性,僅使用控件的ContextMenuStrip屬性來指定整個控制單一的快捷菜單。
•若是您須要多個行或多種細胞的快捷菜單,處理CellContextMenuStripNeeded或RowContextMenuStripNeeded事件。這些事件讓您管理本身的快捷菜單對象,讓您調整性能。
6.3使用自動調整大小高效
行,列和標題能夠自動調整大小的單元格內容的變化,使細胞中的所有內容都沒有剪輯顯示。更改調整大小模式也能夠調整行,列和標題。要肯定正確的大小,DataGridView控件必須檢查每個細胞,它必須適應值。當處理大量數據時,這種分析能夠產生負面影響控制性能的自動調整大小時發生。爲了不性能降低,請遵循下列準則:
•避免使用帶有大量行集的DataGridView控制自動調整大小。若是你使用自動大小調整,只調整的基礎上所顯示的行。在虛擬模式下只使用所顯示的行以及。
對行和列•,使用DataGridViewAutoSizeRowsMode,DataGridViewAutoSizeColumnsMode和DataGridViewAutoSizeColumnMode枚舉的DisplayedCells或DisplayedCellsExceptHeaders領域。
•對於行頭,使用該DataGridViewRowHeadersWidthSizeMode枚舉AutoSizeToDisplayedHeaders或AutoSizeToFirstHeader領域。
爲了得到最大的可擴展性•,關閉自動調整大小尺寸和使用方案。
6.4使用選定的單元格,行和列的集合高效
SelectedCells集合不執行效率大選擇。收藏的SelectedRows和SelectedColumns也能夠是低效的,但在較小的程度,由於有許多比細胞中的行數少一個典型的DataGridView控件,比列行少得多。爲了不性能降低與這些藏品時,請遵循下列準則:
•要肯定是否全部在DataGridView單元格已被選中,而後再訪問該SelectedCells集合的內容,檢查AreAllCellsSelected方法的返回值。請注意,可是,這種方法可能會致使行成爲非共享。有關詳細信息,請參閱下一節。
•避免使用的DataGridViewSelectedCellCollection Count屬性來肯定所選細胞的數量。相反,使用GetCellCount()方法並傳入DataGridViewElementStates.Selected價值。一樣,使用DataGridViewRowCollection.GetRowCount()和DataGridViewColumnCollection.GetColumnCount()方法來肯定所選元素,而不是訪問選定的行和列集合,數量。
•避免細胞爲基礎的選擇模式。相反,SelectionMode屬性設置爲FullRowSelect或FullColumnSelect。
6.5使用共享行
實現有效的內存使用在經過共享行的DataGridView控制。做爲行會分享他們的外觀和行爲,儘量經過DataGridViewRow類的共享實例的信息。
雖然共享行實例節省內存,很容易成爲非共享行。例如,每當一個直接與用戶交互的一個單元,它的行成爲非共享。由於這是沒法避免,在這個主題中的準則是有用的,只有當工做與數據量很是大,只有當用戶將與每個數據你的程序運行時間的一小部分。
阿行不能共享在未綁定的DataGridView控制,若是它的任何單元格包含值。當DataGridView控件綁定到外部數據源,或當您實現虛擬模式,並提供您本身的數據源,該單元格值存儲之外的控制,而不是在單元格對象,容許行被共享。
行對象只能共享,若是它的全部細胞的狀態能夠從該行的狀態和細胞列載的狀態決定。若是您更改單元格的狀態,這樣它能夠再也不從它的行和列的狀態推斷,該行不能被共享。
例如,行不能共享在下列情形之一:
•該行包含一個選定的單元格是否是在選定的列。
•該行包含一個與它的ToolTipText或ContextMenuStrip屬性設置單元。
•該行包含其項目屬性的DataGridViewComboBoxCell集。
在綁定模式或虛擬模式,您能夠經過處理CellToolTipTextNeeded提供CellContextMenuStripNeeded事件和個別細胞工具提示和快捷菜單。
DataGridView控件將自動嘗試使用共享每當行添加到DataGridViewRowCollection行。使用下面的指引,以確保行共享:
•避免調用Add(Object []的)的添加方法和插入(對象[])的插入的行的集合方法重載超載。這些重載自動建立非共享行。
•確保在RowTemplate屬性指定的行能夠在下列狀況下,共享:
當調用add()或Add方法添加或插入(智力,智力)的行的集合插入方法重載(智力)重載。
當增長RowCount屬性的值。
當設置DataSource屬性。
•確保該行的indexSource參數指定當呼叫能夠共享的行集合AddCopy,AddCopies,InsertCopy和InsertCopies方法。
•請肯定指定的行或列時,能夠共享調用Add(的DataGridViewRow)Add方法的重載,AddRange方法,插入(Int32的,的DataGridViewRow)方法重載的插入,和Rows集合InsertRange方法。
要肯定行是不是共享的,使用DataGridViewRowCollection.SharedRow(int)方法來檢索行對象,而後檢查對象的Index屬性。共享行老是爲-1 Index屬性值。
6.6防止行成爲非共享
共享成爲非共享行能夠做爲一個代碼或用戶操做的結果。爲了不影響性能,你應該避免形成行成爲非共享。在應用開發,你能夠處理RowUnshared事件來肯定行成爲非共享。這是很是有用的調試行共享問題。
爲了防止行成爲非共享,請使用下列準則:
•避免索引中的行集或經過它迭代與foreach循環。你不會一般須要直接訪問行。 DataGridView的操做方法,對行,而不是採起行實例行索引參數。此外,對於行相關的事件處理程序接收行屬性,您能夠用它來操做,而不會形成他們成爲非共享行的事件參數對象。
•若是您須要訪問的行對象,請使用DataGridViewRowCollection.SharedRow(int)方法並傳入行的實際索引。請注意,可是,修改一個共享行對象經過此方法檢索將修改全部行共享此對象。在新記錄行不共享,因此這是不會受到影響,當您修改任何其餘行中的其餘行。還要注意的是一個共享行表明不一樣的行可能有不一樣的快捷菜單。以檢索共享行實例的正確快捷菜單中,使用GetContextMenuStrip方法並傳入行的實際索引。若是您訪問共享行的ContextMenuStrip屬性,而是將使用-1共享行的索引,將不檢索正確的快捷菜單。
•避免索引DataGridViewRow.Cells集合。訪問一個細胞將直接致使其父行成爲非共享,實例化一個新的DataGridViewRow。爲細胞相關的事件處理程序接收單元屬性,你能夠用它來操做不會致使行成爲非共享細胞事件參數對象。您也可使用CurrentCellAddress屬性來檢索,而不用訪問細胞直接當前單元格的行和列索引。
•避免細胞爲基礎的選擇模式。這些模式致使行成爲非共享。相反,將SelectionMode屬性設置DataGridViewSelectionMode.FullRowSelect或DataGridViewSelectionMode.FullColumnSelect。
•不處理DataGridViewRowCollection.CollectionChanged或RowStateChanged事件。這些事件會致使行成爲非共享。另外,不要叫DataGridViewRowCollection.OnCollectionChanged(CollectionChangeEventArgs)或OnRowStateChanged(智力,DataGridViewRowStateChangedEventArgs)方法,提升了這些事件。
•不訪問SelectedCells集合時SelectionMode屬性值是FullColumnSelect,ColumnHeaderSelect,FullRowSelect或RowHeaderSelect。這會致使全部行成爲非共享選擇。
•不要調用AreAllCellsSelected(布爾)方法。這種方法可能會致使行成爲非共享。
•不要調用SelectAll方法當SelectionMode屬性值是CellSelect。這會致使全部行成爲非共享。
•不要設置只讀或選定的一對假時,在其列對應的屬性設置爲true單元屬性。這會致使全部行成爲非共享。
•不訪問DataGridViewRowCollection.List財產。這會致使全部行成爲非共享。
•不要調用Sort方法的Sort(IComparer接口)超載。一個自定義比較排序會致使全部行成爲非共享。
該附錄包含的代碼示例和片斷集中解答了前面散落的常見問題:
ReadOnly屬性決定了單元格中的數據是否能夠編輯,能夠設置單元格的ReadOnly 屬性,也能夠設置DataGridViewRow.ReadOnly 或DataGridViewColumn.ReadOnly使得一行或一列所包含的單元格都是隻讀的。 默認狀況下,若是一行或一列是隻讀的,那麼其包含的單元格也會使只讀的。
不過你仍能夠操做一個只讀的單元格,好比選中它,將其設置爲當前單元格,但用戶不能修改單元格的內容。注意,即便單元格經過ReadOnly屬性設置爲只讀,仍然能夠經過編程的方式修改它,另外ReadOnly也不會影響用戶是否能夠刪除行。
單元格能夠設置爲只讀而不可編輯,但DataGridView卻沒提供使單元格不可用的支持。通常意義上,不可用意味着用戶不能進行操做,一般會帶有外觀的暗示,如灰色。沒有一種簡單的方法來建立那種不可操做的單元格,但提供一個暗示性的外觀告訴用戶某單元格不可用仍是可行的。內置的單元格類型沒有進行不可用設置的屬性,下面的例子擴展了DataGridViewButtonCell ,參照常見控件的Enabled屬性,爲其添加了Enabled屬性,若是該屬性設置爲false,那麼其外觀狀態將相似於普通按鈕的不可用狀態。
public class DataGridViewDisableButtonColumn : DataGridViewButtonColumn
{
public DataGridViewDisableButtonColumn()
{
this.CellTemplate = new DataGridViewDisableButtonCell();
}
}
public class DataGridViewDisableButtonCell : DataGridViewButtonCell
{
private bool enabledValue;
public bool Enabled
{
get {
return enabledValue;
}
set {
enabledValue = value;
}
}
// Override the Clone method so that the Enabled property is copied.
public override object Clone()
{
DataGridViewDisableButtonCell cell =
(DataGridViewDisableButtonCell)base.Clone();
cell.Enabled = this.Enabled;
return cell;
}
// By default, enable the button cell.
public DataGridViewDisableButtonCell()
{
this.enabledValue = true;
}
protected override void Paint(Graphics graphics,
Rectangle clipBounds, Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState, object value,
object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
// The button cell is disabled, so paint the border,
// background, and disabled button for the cell.
if (!this.enabledValue)
{
// Draw the cell background, if specified.
if ((paintParts & DataGridViewPaintParts.Background) ==
DataGridViewPaintParts.Background)
{
SolidBrush cellBackground =
new SolidBrush(cellStyle.BackColor);
graphics.FillRectangle(cellBackground, cellBounds);
cellBackground.Dispose();
}
// Draw the cell borders, if specified.
if ((paintParts & DataGridViewPaintParts.Border) ==
DataGridViewPaintParts.Border)
{
PaintBorder(graphics, clipBounds, cellBounds, cellStyle,
advancedBorderStyle);
}
// Calculate the area in which to draw the button.
Rectangle buttonArea = cellBounds;
Rectangle buttonAdjustment =
this.BorderWidths(advancedBorderStyle);
buttonArea.X += buttonAdjustment.X;
buttonArea.Y += buttonAdjustment.Y;
buttonArea.Height -= buttonAdjustment.Height;
buttonArea.Width -= buttonAdjustment.Width;
// Draw the disabled button.
ButtonRenderer.DrawButton(graphics, buttonArea,
PushButtonState.Disabled);
// Draw the disabled button text.
if (this.FormattedValue is String)
{
TextRenderer.DrawText(graphics,
(string)this.FormattedValue,
this.DataGridView.Font,
buttonArea, SystemColors.GrayText);
}
}
else
{
// The button cell is enabled, so let the base class
// handle the painting.
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
elementState, value, formattedValue, errorText,
cellStyle, advancedBorderStyle, paintParts);
}
}
}
默認狀況下DataGridView的操做(navigation)模型在限制用戶將焦點置於指定的單元格方面沒有提供任何支持。你能夠實現本身的操做邏輯,這須要重寫合適的鍵盤、導航、鼠標方法,如DataGridView.OnKeyDown, DataGridView.ProcessDataGridViewKey, DataGridView.SetCurrentCellAddressCore, DataGridView.SetSelectedCellCore, DataGridView.OnMouseDown。
DataGridView 控件只支持在單元格處於編輯狀態時顯示真實的控件(如TextBox)。DataGridView 沒有被設計爲顯示多控件或爲每行重複顯示控件。DataGridView 在單元格不被編輯時爲其繪製對應控件的外觀,該外觀多是你想要的。例如,DataGridViewButtonCell 類型的單元格,無論它是否處於編輯狀態,老是表現爲一個按鈕。
By default, text in a DataGridViewTextBoxCell does not wrap. This can be controlled via the WrapMode property on the cell style (e.g. DataGridView.DefaultCellStyle.WrapMode). Because text doesn’t wrap, new line characters in the text do not apply and so they are displayed as a 「non-printable」 character. This is similar to setting a TextBox’s Text property to the same text when the TextBox’s MultiLine property is false.
DataGridView控件沒有對在同一單元格內同時顯示圖標和文本提供支持。但經過實現自定義的繪製事件,如CellPaint 事件,你能夠輕鬆實現這個效果。
下面這段代碼擴展了DataGridViewTextBoxColumn 和DataGridViewTextBoxCell類,將一個圖片顯示在文本旁邊。這個示例使用了DataGridViewCellStyle.Padding 屬性來調整文本的位置,重寫了Paint 方法來繪製圖片。該示例能夠獲得簡化,方法是處理CellPainting 事件,在這裏實現相似的功能。
public class TextAndImageColumn:DataGridViewTextBoxColumn
{
private Image imageValue;
private Size imageSize;
public TextAndImageColumn()
{
this.CellTemplate = new TextAndImageCell();
}
public override object Clone()
{
TextAndImageColumn c = base.Clone() as TextAndImageColumn;
c.imageValue = this.imageValue;
c.imageSize = this.imageSize;
return c;
}
public Image Image
{
get { return this.imageValue; }
set
{
if (this.Image != value) {
this.imageValue = value;
this.imageSize = value.Size;
if (this.InheritedStyle != null) {
Padding inheritedPadding = this.InheritedStyle.Padding;
this.DefaultCellStyle.Padding = new Padding(imageSize.Width,
inheritedPadding.Top, inheritedPadding.Right,
inheritedPadding.Bottom);
}
}
}
}
private TextAndImageCell TextAndImageCellTemplate
{
get { return this.CellTemplate as TextAndImageCell; }
}
internal Size ImageSize
{
get { return imageSize; }
}
}
public class TextAndImageCell : DataGridViewTextBoxCell
{
private Image imageValue;
private Size imageSize;
public override object Clone()
{
TextAndImageCell c = base.Clone() as TextAndImageCell;
c.imageValue= this.imageValue;
c.imageSize = this.imageSize;
return c;
}
public Image Image
{
get {
if (this.OwningColumn == null ||
this.OwningTextAndImageColumn == null) {
return imageValue;
}
else if (this.imageValue != null) {
return this.imageValue;
}
else {
return this.OwningTextAndImageColumn.Image;
}
}
set {
if (this.imageValue != value) {
this.imageValue = value;
this.imageSize = value.Size;
Padding inheritedPadding = this.InheritedStyle.Padding;
this.Style.Padding = new Padding(imageSize.Width,
inheritedPadding.Top, inheritedPadding.Right,
inheritedPadding.Bottom);
}
}
}
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
// Paint the base content
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState,
value, formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts);
if (this.Image != null) {
// Draw the image clipped to the cell.
System.Drawing.Drawing2D.GraphicsContainer container =
graphics.BeginContainer();
graphics.SetClip(cellBounds);
graphics.DrawImageUnscaled(this.Image, cellBounds.Location);
graphics.EndContainer(container);
}
}
private TextAndImageColumn OwningTextAndImageColumn
{
get { return this.OwningColumn as TextAndImageColumn; }
}
}
有時但願僅顯示DataGridView的部分列,將其它列隱藏。好比DataGridView含有一列包含員工薪水信息,你可能但願僅將這些信息顯示給具備必定信用級別的人,其餘人則隱藏。
經過編程方式隱藏
DataGridViewColumn類的Visible 屬性決定了是否顯示該列。
經過設計器隱藏
1) 右擊DataGridView控件,選擇Edit Columns;
2) 在列列表中選擇一列;
3) 在列屬性網格中,將Visible屬性設置爲false。
對於DataGridView 控件,默認狀況下,TextBox類型的列會自動排序,而其它類型的列則不會自動排序。這種自動排序有時會把數據變得比較亂,這時你會想更改這些默認設置。
DataGridViewColumn的屬性SortMode決定了列的排序方式,將其設置爲DataGridViewColumnSortMode.NotSortable就能夠避免默認的排序行爲。
默認狀況下DataGridView不支持針對多列排序。下面針對是否將數據綁定到DataGridView來分別演示如何爲其添加多列排序功能。
9.1 將數據綁定到DataGridView時
DataGridView進行數據綁定的時候,數據源(如DataView)可對多個列排序。DataGridView會保留這種排序,但只有第一個排序列會顯示排序符號(向上或向下的箭頭),此外SortedColumn屬性也只會返回第一個排序列。
一些數據源內置了對多列排序的支持。若是你的數據源實現了IBindingListView接口,提供了對Sort屬性的支持,那麼該數據源就支持多列排序。爲了明確指出DataGridView對多列排序,手動爲已排序列設置正確的SortGlyphDirection屬性,指示該列已經排序。
下面這個示例使用DataTable做爲數據源,使用其DefaultView的 Sort 屬性對第二列和第三列排序;該示例同時演示瞭如何設置列的SortGlyphDirection屬性。該示例假定在你的窗體上有一個DataGridView控件和一個BindingSource組件:
DataTable dt = new DataTable();
dt.Columns.Add("C1", typeof(int));
dt.Columns.Add("C2", typeof(string));
dt.Columns.Add("C3", typeof(string));
dt.Rows.Add(1, "1", "Test1");
dt.Rows.Add(2, "2", "Test2");
dt.Rows.Add(2, "2", "Test1");
dt.Rows.Add(3, "3", "Test3");
dt.Rows.Add(4, "4", "Test4");
dt.Rows.Add(4, "4", "Test3");
DataView view = dt.DefaultView;
view.Sort = "C2 ASC, C3 ASC";
bindingSource.DataSource = view;
DataGridViewTextBoxColumn col0 = new DataGridViewTextBoxColumn();
col0.DataPropertyName = "C1";
dataGridView1.Columns.Add(col0);
col0.SortMode = DataGridViewColumnSortMode.Programmatic;
col0.HeaderCell.SortGlyphDirection = SortOrder.None;
DataGridViewTextBoxColumn col1 = new DataGridViewTextBoxColumn();
col1.DataPropertyName = "C2";
dataGridView1.Columns.Add(col1);
col1.SortMode = DataGridViewColumnSortMode.Programmatic;
col1.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
DataGridViewTextBoxColumn col2 = new DataGridViewTextBoxColumn();
col2.DataPropertyName = "C3";
dataGridView1.Columns.Add(col2);
col2.SortMode = DataGridViewColumnSortMode.Programmatic;
col2.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
9.2 Unbound DataGridView
To provide support for sorting on multiple columns you can handle the SortCompare event or call the Sort(IComparer) overload of the Sort method for greater sorting flexibility.
9.2.1 Custom Sorting Using the SortCompare Event
The following code example demonstrates custom sorting using a SortCompare event handler. The selected DataGridViewColumn is sorted and, if there are duplicate values in the column, the ID column is used to determine the final order.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
class Form1 : Form
{
private DataGridView dataGridView1 = new DataGridView();
// Establish the main entry point for the application.
[STAThreadAttribute()]
static voidMain()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
// Initialize the form.
// This code can be replaced with designer generated code.
dataGridView1.AllowUserToAddRows = false;
dataGridView1.Dock = DockStyle.Fill;
dataGridView1.SortCompare += new DataGridViewSortCompareEventHandler(
this.dataGridView1_SortCompare);
Controls.Add(this.dataGridView1);
this.Text = "DataGridView.SortCompare demo";
PopulateDataGridView();
}
// Replace this with your own population code.
public void PopulateDataGridView()
{
// Add columns to the DataGridView.
dataGridView1.ColumnCount = 3;
// Set the properties of the DataGridView columns.
dataGridView1.Columns[0].Name = "ID";
dataGridView1.Columns[1].Name = "Name";
dataGridView1.Columns[2].Name = "City";
dataGridView1.Columns["ID"].HeaderText = "ID";
dataGridView1.Columns["Name"].HeaderText = "Name";
dataGridView1.Columns["City"].HeaderText = "City";
// Add rows of data to the DataGridView.
dataGridView1.Rows.Add(new string[] { "1", "Parker", "Seattle" });
dataGridView1.Rows.Add(new string[] { "2", "Parker", "New York" });
dataGridView1.Rows.Add(new string[] { "3", "Watson", "Seattle" });
dataGridView1.Rows.Add(new string[] { "4", "Jameson", "New Jersey" });
dataGridView1.Rows.Add(new string[] { "5", "Brock", "New York" });
dataGridView1.Rows.Add(new string[] { "6", "Conner", "Portland" });
// Autosize the columns.
dataGridView1.AutoResizeColumns();
}
private void dataGridView1_SortCompare(object sender,
DataGridViewSortCompareEventArgs e)
{
// Try to sort based on the cells in the current column.
e.SortResult = System.String.Compare(
e.CellValue1.ToString(), e.CellValue2.ToString());
// If the cells are equal, sort based on the ID column.
if (e.SortResult == 0 && e.Column.Name != "ID")
{
e.SortResult = System.String.Compare(
dataGridView1.Rows[e.RowIndex1].Cells["ID"].Value.ToString(),
dataGridView1.Rows[e.RowIndex2].Cells["ID"].Value.ToString());
}
e.Handled = true;
}
}
9.2.2 Custom Sorting Using the IComparer Interface
The following code example demonstrates custom sorting using the Sort(IComparer) overload of the Sort method, which takes an implementation of the IComparer interface to perform a multiple-column sort.
using System;
using System.Drawing;
using System.Windows.Forms;
class Form1 : Form
{
private DataGridView DataGridView1 = new DataGridView();
private FlowLayoutPanel FlowLayoutPanel1 = new FlowLayoutPanel();
private Button Button1 = new Button();
private RadioButton RadioButton1 = new RadioButton();
private RadioButton RadioButton2 = new RadioButton();
// Establish the main entry point for the application.
[STAThreadAttribute()]
public static voidMain()
{
Application.Run(new Form1());
}
public Form1()
{
// Initialize the form.
// This code can be replaced with designer generated code.
AutoSize = true;
Text = "DataGridView IComparer sort demo";
FlowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
FlowLayoutPanel1.Location = new System.Drawing.Point(304, 0);
FlowLayoutPanel1.AutoSize = true;
FlowLayoutPanel1.Controls.Add(RadioButton1);
FlowLayoutPanel1.Controls.Add(RadioButton2);
FlowLayoutPanel1.Controls.Add(Button1);
Button1.Text = "Sort";
RadioButton1.Text = "Ascending";
RadioButton2.Text = "Descending";
RadioButton1.Checked = true;
Controls.Add(FlowLayoutPanel1);
Controls.Add(DataGridView1);
}
protected override void OnLoad(EventArgs e)
{
PopulateDataGridView();
Button1.Click += new EventHandler(Button1_Click);
base.OnLoad(e);
}
// Replace this with your own code to populate the DataGridView.
private void PopulateDataGridView()
{
DataGridView1.Size = new Size(300, 300);
// Add columns to the DataGridView.
DataGridView1.ColumnCount = 2;
// Set the properties of the DataGridView columns.
DataGridView1.Columns[0].Name = "First";
DataGridView1.Columns[1].Name = "Last";
DataGridView1.Columns["First"].HeaderText = "First Name";
DataGridView1.Columns["Last"].HeaderText = "Last Name";
DataGridView1.Columns["First"].SortMode =
DataGridViewColumnSortMode.Programmatic;
DataGridView1.Columns["Last"].SortMode =
DataGridViewColumnSortMode.Programmatic;
// Add rows of data to the DataGridView.
DataGridView1.Rows.Add(new string[] { "Peter", "Parker" });
DataGridView1.Rows.Add(new string[] { "James", "Jameson" });
DataGridView1.Rows.Add(new string[] { "May", "Parker" });
DataGridView1.Rows.Add(new string[] { "Mary", "Watson" });
DataGridView1.Rows.Add(new string[] { "Eddie", "Brock" });
}
private void Button1_Click(object sender, EventArgs e)
{
if (RadioButton1.Checked == true)
{
DataGridView1.Sort(new RowComparer(SortOrder.Ascending));
}
else if (RadioButton2.Checked == true)
{
DataGridView1.Sort(new RowComparer(SortOrder.Descending));
}
}
private class RowComparer : System.Collections.IComparer
{
private static int sortOrderModifier = 1;
public RowComparer(SortOrder sortOrder)
{
if (sortOrder == SortOrder.Descending)
{
sortOrderModifier = -1;
}
else if (sortOrder == SortOrder.Ascending)
{
sortOrderModifier = 1;
}
}
public int Compare(object x, object y)
{
DataGridViewRow DataGridViewRow1 = (DataGridViewRow)x;
DataGridViewRow DataGridViewRow2 = (DataGridViewRow)y;
// Try to sort based on the Last Name column.
int CompareResult = System.String.Compare(
DataGridViewRow1.Cells[1].Value.ToString(),
DataGridViewRow2.Cells[1].Value.ToString());
// If the Last Names are equal, sort based on the First Name.
if (CompareResult == 0)
{
CompareResult = System.String.Compare(
DataGridViewRow1.Cells[0].Value.ToString(),
DataGridViewRow2.Cells[0].Value.ToString());
}
return CompareResult * sortOrderModifier;
}
}
}
有時候你須要處理單元格包含的編輯控件的特定事件。你須要處理DataGridView.EditingControlShowing 事件,它的第二個參數的Control屬性能讓你訪問該單元格包含的編輯控件。若是你要處理的事件不屬於它的基類Control,還須要將該控件轉換爲特定的控件(通常爲ComboBox控件或TextBox控件)。
注意:若是類型相同,DataGridView會重用該編輯控件,所以,你應該確保不會添加已存在的事件處理函數,不然會調用相同的函數屢次(能夠在添加前先將其移除,請參考個人示例代碼)。
若是你只是想臨時爲編輯控件添加事件處理函數(多是針對特定列的特定單元格),你能夠在CellEndEdit事件中移除該處理函數。你也能夠在添加以前移除任何已存在的事件處理函數。
有時知道用戶什麼時候選擇了ComboBox編輯控件的項(item)會比較有用。對於窗體上的ComboBox 控件,你一般會處理它的SelectedIndexChanged事件,對於DataGridViewComboBox,經過處理DataGridView.EditingControlShowing事件你能夠完成相同的事情。下面這段示例代碼演示了這一點。注意:它同時也演示瞭如何避免添加多個相同的事件處理函數(即在添加前先移除已存在的事件處理函數,能夠參考問題11)。
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
ComboBox cb = e.Control as ComboBox;
if (cb != null)
{
// first remove event handler to keep from attaching multiple:
cb.SelectedIndexChanged -= new
EventHandler(cb_SelectedIndexChanged);
// now attach the event handler
cb.SelectedIndexChanged += new
EventHandler(cb_SelectedIndexChanged);
}
}
void cb_SelectedIndexChanged(object sender, EventArgs e)
{
MessageBox.Show("Selected index changed");
}
經過拖放調整行的順序不是DataGridView的內置功能,但使用標準的拖放處理代碼,你能夠很容易的實現這個功能。下面這個代碼片段演示了這個過程,假定你的窗體上有一個name爲dataGridView1的DataGridView,它的AllowDrop屬性爲true,還要爲它添加必要的事件處理方法。(我試運行了這段代碼,若是經過數據綁定爲DataGridView添加數據,那麼下面的代碼將不會生效,由於它只能爲非綁定方式添加的行排序,若是要以綁定方式添加數據,請參看個人示例程序)
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
DragDropEffects dropEffect = dataGridView1.DoDragDrop(
dataGridView1.Rows[rowIndexFromMouseDown],
DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
// Remember the point where the mouse down occurred.
// The DragSize indicates the size that the mouse can move
// before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)),
dragSize);
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
// The mouse locations are relative to the screen, so they must be
// converted to client coordinates.
Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));
// Get the row index of the item the mouse is below.
rowIndexOfItemUnderMouseToDrop =
dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
// If the drag operation was a move then remove and insert the row.
if (e.Effect== DragDropEffects.Move)
{
DataGridViewRow rowToMove = e.Data.GetData(
typeof(DataGridViewRow)) as DataGridViewRow;
dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
}
}
以默認方式填充DataGridView時,可能會發生因列的寬度不夠,而暴露出控件的灰色背景的狀況,很不美觀。將最後一列的AutoSizeMode屬性設置爲Fill會使該列調整大小來填充網格的剩餘客戶區(client area)。做爲一個可選的方式,你能夠設置最後一列MinimumWidth屬性,以保持該列的寬度不至於過小。
默認狀況下,DataGridViewTextBoxCell不支持換行,這個能夠由DataGridViewCellStyle的WrapMode屬性來控制。 (如DataGridView.DefaultCellStyle.WrapMode)。將WrapMode 屬性DataGridViewTriState枚舉的三個取值之一。
下面的代碼示例使用DataGridView.DefaultCellStyle屬性設置整個控件所包含的單元格的WrapMode屬性(即設置全部單元格的換行模式)。
this.dataGridView1.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
默認狀況下Image類型的列和單元格將null值轉換爲標準的「X」圖像( ),將Image列的NullValue屬性設置爲null可以使該列不顯示任何圖像。下面這行代碼演示瞭如何設置Image列的NullValue屬性。
this.dataGridViewImageColumn1.DefaultCellStyle.NullValue = null;
默認狀況下,DataGridViewComboBoxCell不接受用戶的輸入值。但有時確實有向ComboxBox輸入數據的須要。實現這個功能,你須要作兩件事。一是將ComboBox編輯控件的DropDownStyle屬性設置爲DropDown,使用戶能夠進行輸入(不然只能進行選擇);二是確保用戶輸入的值可以添加到ComboBox的Items集合。這是由於ComboBoxCell的值必須在Items集合中,不然會觸發DataError事件(參看3.5.1節),而適合添加新值到Items集合的地方是CellValidating事件處理函數:
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex == comboBoxColumn.DisplayIndex)
{
if (!this.comboBoxColumn.Items.Contains(e.FormattedValue))
{
this.comboBoxColumn.Items.Add(e.FormattedValue);
}
}
}
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
if (this.dataGridView1.CurrentCellAddress.X == comboBoxColumn.DisplayIndex)
{
ComboBox cb = e.Control as ComboBox;
if (cb != null)
{
cb.DropDownStyle = ComboBoxStyle.DropDown;
}
}
}
Sometimes data that you want to display in the DataGridView has a relationship between two tables such as a category and subcategory. You want to let the user select the category and then choose between a subcategory based upon the category. This is possible with the DataGridView by using two combo box columns. To enable this, two versions of the filtered list (subcategory) needs to be created. One list has no filter applied while the other one will be filtered only when the user is editing a subcategory cell. Two lists are required due to the requirement described in 3.5.1 section that a combo box cells value must be in the items collection or else a DataError event is raised. In this case, since all combo box cells in the column use the same datasource if you filter the datasource for one row then a combo box cell in another row might not have its value visible in the datasource, thus causing a DataError event.
The below example uses the Northwind database to display related data from the Territory and Region tables (a territory is in a specific region.) Using the category and subcategory concept, the Region is the category and the Territory is the subcategory.
private void Form1_Load(object sender, EventArgs e)
{
this.territoriesTableAdapter.Fill(this.northwindDataSet.Territories);
this.regionTableAdapter.Fill(this.northwindDataSet.Region);
// Setup BindingSource for filtered view.
filteredTerritoriesBS = new BindingSource();
DataView dv = new DataView(northwindDataSet.Tables["Territories"]);
filteredTerritoriesBS.DataSource = dv;
}
private void dataGridView1_CellBeginEdit(object sender,
DataGridViewCellCancelEventArgs e)
{
if (e.ColumnIndex == territoryComboBoxColumn.Index)
{
// Set the combobox cell datasource to the filtered BindingSource
DataGridViewComboBoxCell dgcb = (DataGridViewComboBoxCell)dataGridView1
[e.ColumnIndex, e.RowIndex];
dgcb.DataSource = filteredTerritoriesBS;
// Filter the BindingSource based upon the region selected
this.filteredTerritoriesBS.Filter = "RegionID = " +
this.dataGridView1[e.ColumnIndex - 1, e.RowIndex].Value.ToString();
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == this.territoryComboBoxColumn.Index)
{
// Reset combobox cell to the unfiltered BindingSource
DataGridViewComboBoxCell dgcb = (DataGridViewComboBoxCell)dataGridView1
[e.ColumnIndex, e.RowIndex];
dgcb.DataSource = territoriesBindingSource; //unfiltered
this.filteredTerritoriesBS.RemoveFilter();
}
}
在使用錯誤文本和圖標時,有時你但願爲用戶提供一個即時反饋,以提示當前的輸入不正確。默認狀況下,即便設置了ErrorText屬性,若是單元格仍處於編輯模式下,那麼錯誤圖標也不會顯示,好比TextBox和ComboBox。
下面的示例演示瞭如何在CellValidating事件中填充(padding)一個單元格爲錯誤圖標提供空間。由於默認狀況下填充行爲會影響錯誤圖標的位置,該示例(TODO)。The below sample demonstrates how you can set a cell’s padding in the CellValidating event to provide spacing for the error icon. Since padding by default affects the location of the error icon the sample uses the CellPainting to move the position of the icon for painting. Lastly, the sample uses the tooltip control to display a custom tooltip when the mouse is over the cell to indicate what the problem is. This sample could also be written as a custom cell that overrides GetErrorIconBounds method to provide a location for the error icon that was independent of the padding.
private ToolTip errorTooltip;
private Point cellInError = new Point(-2, -2);
public Form1()
{
InitializeComponent();
dataGridView1.ColumnCount = 3;
dataGridView1.RowCount = 10;
}
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
if (e.FormattedValue.ToString() == "BAD")
{
DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
cell.ErrorText = "Invalid data entered in cell";
// increase padding for icon. This moves the editing control
if (cell.Tag == null)
{
cell.Tag = cell.Style.Padding;
cell.Style.Padding = new Padding(0, 0, 18, 0);
cellInError = new Point(e.ColumnIndex, e.RowIndex);
}
if (errorTooltip == null)
{
errorTooltip = new ToolTip();
errorTooltip.InitialDelay = 0;
errorTooltip.ReshowDelay = 0;
errorTooltip.Active = false;
}
e.Cancel = true;
}
}
}
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (dataGridView1.IsCurrentCellDirty && !String.IsNullOrEmpty(e.ErrorText))
{
// paint everything except error icon
e.Paint(e.ClipBounds, DataGridViewPaintParts.All &
~(DataGridViewPaintParts.ErrorIcon));
// now move error icon over to fill in the padding space
GraphicsContainer container = e.Graphics.BeginContainer();
e.Graphics.TranslateTransform(18, 0);
e.Paint(this.ClientRectangle, DataGridViewPaintParts.ErrorIcon);
e.Graphics.EndContainer(container);
e.Handled = true;
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1[e.ColumnIndex, e.RowIndex].ErrorText != String.Empty)
{
DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
cell.ErrorText = String.Empty;
cellInError = new Point(-2,-2);
// restore padding for cell. This moves the editing control
cell.Style.Padding = (Padding)cell.Tag;
// hide and dispose tooltip
if (errorTooltip != null)
{
errorTooltip.Hide(dataGridView1);
errorTooltip.Dispose();
errorTooltip = null;
}
}
}
// show and hide the tooltip for error
private void dataGridView1_CellMouseMove(object sender,
DataGridViewCellMouseEventArgs e)
{
if (cellInError.X == e.ColumnIndex &&
cellInError.Y == e.RowIndex)
{
DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
if (cell.ErrorText != String.Empty)
{
if (!errorTooltip.Active)
{
errorTooltip.Show(cell.ErrorText, dataGridView1, 1000);
}
errorTooltip.Active = true;
}
}
}
private void dataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
if (cellInError.X == e.ColumnIndex &&
cellInError.Y == e.RowIndex)
{
if (errorTooltip.Active)
{
errorTooltip.Hide(dataGridView1);
errorTooltip.Active = false;
}
}
}
The data you display in the DataGridView control will normally come from a data source of some kind, but you might want to display a column of data that does not come from the data source. This kind of column is called an unbound column. Unbound columns can take many forms. As discussed in the data section above, you can use virtual mode to display additional data along with bound data.
The following code example demonstrates how to create an unbound column of check box cells to enable the user to select database records to process. The grid is put into virtual mode and responds to the necessary events. The selected records are kept by ID in a dictionary to allow the user to sort the content but not lose the checked rows.
private System.Collections.Generic.Dictionary<int, bool> checkState;
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = customerOrdersBindingSource;
// The check box column will be virtual.
dataGridView1.VirtualMode = true;
dataGridView1.Columns.Insert(0, new DataGridViewCheckBoxColumn());
// Initialize the dictionary that contains the boolean check state.
checkState = new Dictionary<int, bool>();
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// Update the status bar when the cell value changes.
if (e.ColumnIndex == 0 && e.RowIndex != -1)
{
// Get the orderID from the OrderID column.
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
checkState[orderID] = (bool)dataGridView1.Rows[e.RowIndex].Cells[0].Value;
}
private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
// Handle the notification that the value for a cell in the virtual column
// is needed. Get the value from the dictionary if the key exists.
if (e.ColumnIndex == 0)
{
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
if (checkState.ContainsKey(orderID))
{
e.Value = checkState[orderID];
}
else
e.Value = false;
}
}
private void dataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
{
// Handle the notification that the value for a cell in the virtual column
// needs to be pushed back to the dictionary.
if (e.ColumnIndex == 0)
{
// Get the orderID from the OrderID column.
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
// Add or update the checked value to the dictionary depending on if the
// key (orderID) already exists.
if (!checkState.ContainsKey(orderID))
{
checkState.Add(orderID, (bool)e.Value);
}
else
checkState[orderID] = (bool)e.Value;
}
}
The DataGridView does not provide any new features apart from virtual mode to enable this. What you can do is use the JoinView class described in the following article http://support.microsoft.com/default.aspx?scid=kb;en-us;325682. Using this class you can join two or more DataTables together. This JoinView can then be databound to the DataGridView.
使用DataGridView時最多見的狀況之一就是主從表單,這時要顯示具備主從關係的兩個數據表。在主表中選擇一行記錄,從表中也會隨之變化,顯示相應的記錄。
經過DataGridView控件和BindingSource 組件的交互做用來實現主從表單是很是簡單的。下面的示例演示的是SQL Server的範例數據庫Northwind 中的兩個表:Customers 和Orders。在主DataGridView中選擇一個顧客,那麼該顧客的全部訂單會顯示在從DataGridView 中。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
private DataGridView masterDataGridView = new DataGridView();
private BindingSource masterBindingSource = new BindingSource();
private DataGridView detailsDataGridView = new DataGridView();
private BindingSource detailsBindingSource = new BindingSource();
[STAThreadAttribute()]
public static voidMain()
{
Application.Run(new Form1());
}
// Initializes the form.
public Form1()
{
masterDataGridView.Dock = DockStyle.Fill;
detailsDataGridView.Dock = DockStyle.Fill;
SplitContainer splitContainer1 = new SplitContainer();
splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.Panel1.Controls.Add(masterDataGridView);
splitContainer1.Panel2.Controls.Add(detailsDataGridView);
this.Controls.Add(splitContainer1);
this.Load += new System.EventHandler(Form1_Load);
this.Text = "DataGridView master/detail demo";
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Bind the DataGridView controls to the BindingSource
// components and load the data from the database.
masterDataGridView.DataSource = masterBindingSource;
detailsDataGridView.DataSource = detailsBindingSource;
GetData();
// Resize the master DataGridView columns to fit the newly loaded data.
masterDataGridView.AutoResizeColumns();
// Configure the details DataGridView so that its columns automatically
// adjust their widths when the data changes.
detailsDataGridView.AutoSizeColumnsMode =
DataGridViewAutoSizeColumnsMode.AllCells;
}
private void GetData()
{
try
{
// Specify a connection string. Replace the given value with a
// valid connection string for a Northwind SQL Server sample
// database accessible to your system.
String connectionString =
"Integrated Security=SSPI;Persist Security Info=False;" +
"Initial Catalog=Northwind;Data Source=localhost";
SqlConnection connection = new SqlConnection(connectionString);
// Create a DataSet.
DataSet data = new DataSet();
data.Locale = System.Globalization.CultureInfo.InvariantCulture;
// Add data from the Customers table to the DataSet.
SqlDataAdapter masterDataAdapter = new
SqlDataAdapter("select * from Customers", connection);
masterDataAdapter.Fill(data, "Customers");
// Add data from the Orders table to the DataSet.
SqlDataAdapter detailsDataAdapter = new
SqlDataAdapter("select * from Orders", connection);
detailsDataAdapter.Fill(data, "Orders");
// Establish a relationship between the two tables.
DataRelation relation = new DataRelation("CustomersOrders",
data.Tables["Customers"].Columns["CustomerID"],
data.Tables["Orders"].Columns["CustomerID"]);
data.Relations.Add(relation);
// Bind the master data connector to the Customers table.
masterBindingSource.DataSource = data;
masterBindingSource.DataMember = "Customers";
// Bind the details data connector to the master data connector,
// using the DataRelation name to filter the information in the
// details table based on the current row in the master table.
detailsBindingSource.DataSource = masterBindingSource;
detailsBindingSource.DataMember = "CustomersOrders";
}
catch (SqlException)
{
MessageBox.Show("To run this example, replace the value of the " +
"connectionString variable with a connection string that is " +
"valid for your system.");
}
}
}
DataGridView 不支持在同一DataGridView 中顯示主從表。Windows Forms的先前版本中的DataGrid控件或許是你須要的一個解決方案。
對於DataGridView 控件,默認狀況下,TextBox類型的列會自動排序,而其它類型的列則不會自動排序。這種自動排序有時會把數據變得比較亂,這時你會想更改這些默認設置。
DataGridViewColumn的屬性SortMode決定了列的排序方式,將其設置爲DataGridViewColumnSortMode.NotSortable就能夠避免默認的排序行爲。
默認狀況下,操做工具欄或菜單不會致使對控件的驗證。但對於綁定控件來講,提交數據前進行驗證是必要的。而一旦窗體和其中的全部控件獲得驗證,當前編輯過的數據就須要提交。最後,數據適配器(如SqlDataAdapter)須要將數據的修改寫入數據庫。要達到這個效果,將下面三行代碼加到相應的事件處理函數(指工具欄按鈕或菜單項的事件)內:
this.Validate();
this.customersBindingSource.EndEdit(); this.customersTableAdapter.Update(this.northwindDataSet.Customers);
當用戶選擇DataGridView的一行,按下Delete鍵時就會觸發UserDeletingRow 事件。你能夠提示用戶是否肯定要刪除該行記錄,建議僅在用戶要刪除已存在的記錄(而不是用戶添加的新行)時才進行這種提示。將下面這些代碼添加到UserDeletingRow事件的處理方法中就能夠實現這種功能:
if (!e.Row.IsNewRow)
{
DialogResult response = MessageBox.Show("Are you sure?", "Delete row?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
if (response == DialogResult.No)
e.Cancel = true;
}