天天看點

DataGridView控件使用方法1          何為DataGridView2          DataGridView的結構3          列/單元格類型揭密(column/cell types)4          操作資料(Working with Data)5          特性綜覽(Overview of features)6          最佳實踐(Best Practices)附錄 A – FAQ

DataGridView控件

DataGridView是用于Windows Froms 2.0的新網格控件。它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支援很多我們的使用者需要的特性。

關于本文檔:

本文檔不準備面面俱到地介紹DataGridView,而是着眼于深入地介紹一些技術點的進階特性。

本文檔按邏輯分為5個章節,首先是結構和特性的概覽,其次是内置的列/單元格類型的介紹,再次是資料操作相關的内容,然後是主要特性的綜述,最後是最佳實踐。

大部分章節含有一個“Q & A”部分,來回答該章節相關的一些常見問題。注意,某些問題會由于知識點的關聯性重複出現在多個章節。這些問題、答案及其附帶的示例代碼都包含在本文檔的附錄部分。

内容

1     何為DataGridView.. 4

1.1    DataGridView和DataGrid 之間的差別... 4

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

1          何為DataGridView

通過DataGridView控件,可以顯示和編輯表格式的資料,而這些資料可以取自多種不同類型的資料源。

DataGridView控件具有很高的的可配置性和可擴充性,提供了大量的屬性、方法和事件,可以用來對該控件的外觀和行為進行自定義。當你需要在WinForm應用程式中顯示表格式資料時,可以優先考慮DataGridView(相比于DataGrid等其它控件)。如果你要在小型網格中顯示隻讀資料,或者允許使用者編輯數以百萬計的記錄,DataGridView将為你提供一個易于程式設計和良好性能的解決方案。

DataGridView 用來替換先前版本中的DataGrid,擁有較DataGrid更多的功能;但DataGrid仍然得到保留,以備向後相容和将來使用。如果你要在兩者中選擇,可以參考下面給出的DataGrid 和DataGridView之間差別的細節資訊。

1.1       DataGridView和DataGrid 之間的差別

DataGridView提供了大量的DataGrid所不具備的基本功能和進階功能。此外,DataGridView 的結構使得它較之DataGrid控件更容易擴充和自定義。

下表描述了DataGridView提供而DataGrid未提供的幾個主要功能。

DataGridView功能 描述
多種列類型 與DataGrid相比,DataGridView 提供了更多的内置列類型。這些列類型能夠滿足大部分常見需要,而且比DataGrid中的列類型易于擴充或替換。
多種資料顯示方式 DataGrid僅限于顯示外部資料源的資料。而DataGridView則能夠顯示非綁定的資料,綁定的資料源,或者同時顯示綁定和非綁定的資料。你也可以在DataGridView中實作virtual mode,實作自定義的資料管理。
用于自定義資料顯示的多種方式 DataGridView提供了很多屬性和事件,用于資料的格式化和顯示。比如,你可以根據單元格、行和列的内容改變其外觀,或者使用一種類型的資料替代另一種類型的資料。
用于更改單元格、行、列、表頭外觀和行為的多個選項 DataGridView使你能夠以多種方式操作單個網格元件。比如,你可以當機行和列,避免它們因滾動而不可見;隐藏行、列、表頭;改變行、列、表頭尺寸的調整方式;為單個的單元格、行和列提供工具提示(ToolTip)和快捷菜單。

唯一的一個DataGrid提供而DataGridView未提供的特性是兩個相關表中資料的分層次顯示(比如常見的主從表顯示)。你必須使用兩個DataGridView來顯示具有主從關系的兩個表的資料。

1.2       DataGridView的亮點

下表着重顯示了DataGridView的主要特性,稍後會介紹它們的詳細資訊。

DataGridView控件特性 描述
多種列類型 DataGridView提供有TextBox、CheckBox、Image、Button、ComboBox和Link類型的列及相應的單元格類型。
多種資料顯示方式 DataGrid僅限于顯示外部資料源的資料。而DataGridView則能夠顯示非綁定的資料,綁定的資料源,或者同時顯示綁定和非綁定的資料。你也可以在DataGridView中實作virtual mode,實作自定義的資料管理。
自定義資料的顯示和操作的多種方式

DataGridView提供了很多屬性和事件,用于資料的格式化和顯示。

此外,DataGridView提供了操作資料的多種方式,比如,你可以:

  • 對資料排序,并顯示相應的排序符号(帶方向的箭頭表示升降序)
  • 對行、列和單元格的多種選擇模式;多項選擇和單項選擇
  • 以多種格式将資料拷貝到剪貼闆,包括text,CSV (以逗号隔開的值) 和 HTML
  • 改變使用者編輯單元格内容的方式
用于更改單元格、行、列、表頭外觀和行為的多個選項 DataGridView使你能夠以多種方式操作單個網格元件。比如,你可以:
  • 當機行和列,避免它們因滾動而不可見;
  • 隐藏行、列、表頭;
  • 改變行、列、表頭尺寸的調整方式;
  • 改變使用者對行、列、單元格的選擇模式;
  • 為單個的單元格、行和列提供工具提示(ToolTip)和快捷菜單。
  • 自定義單元格、行和列的邊框樣式。
提供豐富的可擴充性的支援 DataGridView提供易于對網格進行擴充和自定義的基礎結構,比如:
  • 處理自定義的繪制事件可以為單元格、列和行提供自定義的觀感;
  • 繼承一個内置的單元格類型以為其提供更多的行為;
  • 實作自定義的接口以提供新的編輯體驗。

2          DataGridView的結構

DataGridView及其相關類被設計為用于顯示和編輯表格資料式資料的靈活的、可擴充的體系。這些類都位于system.Windows.Forms命名空間,它們的名稱也都有共同的字首"DataGridView"。

2.1       結構元素(Architecture Elements)

主要的DataGridView相關類繼承自DataGridViewElement類。

DataGridViewElement類有兩個屬性,一是DataGridView,該屬性提供了對其所屬的DataGridView的引用;二是State,該屬性表示目前的狀态,其值為DataGridViewElementStates枚舉,該枚舉支援位運算,這意味着可以設定組合狀态。

2.2       單元格群組(Cells and Bands)

DataGridView由兩種基本的對象組成:單元格(cell)群組(band)。所有的單元格都繼承自DataGridViewCell基類。 兩種類型的組(或稱集合)DataGridViewColumn和DataGridViewRow都繼承自DataGridViewBand 基類,表示一組結合在一起的單元格。

DataGridView會與一些類進行互操作,但最常打交道的則是如下三個:DataGridViewCell, DataGridViewColumn,DataGridViewRow。

2.3       DataGridView的單元格 (DataGridViewCell)

單元格(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或者它的某個子類來滿足這些要求。

2.3.1       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事件。

2.3.2       常見問題

1)       如何使指定的單元格不可編輯?

2)       如何讓一個單元格不可用(disable)?

3)       如何避免使用者将焦點設定到指定的單元格?

4)       如何使所有單元格總是顯示控件(不論它們是否處于編輯狀态)?

5)       Why does the cell text show up with “square” characters where they should be new lines?

6)       如何在單元格内同時顯示圖示和文本?

2.4       DataGridView的列(DataGridViewColumn)

DataGridView所附帶的資料(這些資料可以通過綁定或非綁定方式附加到控件)的結構表現為DataGridView的列。你可以使用DataGridView的Columns集合屬性通路DataGridView所包含的列,使用SelectedColumns 集合屬性通路目前選中的列。

DataGridViewColumn 類圖 Column 相關類和屬性

一些主要的單元格類型擁有相應的列類型,這些列類型繼承自DataGridViewColumn基類。

常見問題:

1)       如何隐藏一列?

2)       如何避免使用者對列排序?

3)       如何針對多個列排序?

2.5       DataGridView的編輯控件(Editing Controls)

支援進階編輯功能的單元格一般都使用一個繼承自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)

1)       如何為編輯控件添加事件處理函數?

2)       應在何時移除編輯控件的事件處理函數?

3)       如何處理ComboBox列中Combox控件的SelectIndexChanged事件?

4)       如何使所有單元格總是顯示控件(不論它是否處于編輯狀态)?

2.6       DataGridViewRow

DataGridViewRow類用于顯示資料源的一行資料。可以通過DataGridView控件的Rows集合屬性來通路其包含的行,通過SelectedRows集合屬性通路目前選中的行。

DataGridViewRow類圖 Row相關的類和屬性

你可以繼承DataGridViewRow類來實作自己的行類型,雖然多數情況下這并不必要。DataGridView 有幾個行相關的事件和屬性,用以自定義其包含的DataGridViewRow對象的行為。

如果你将DataGridView的AllowUserToAddRows屬性設為true,一個專用于添加新行的特殊行會出現在最後一行的位置上,這一行也屬于Rows集合,但它有一些需要你提起注意的特殊功能,要獲得這方面的更多資訊,請參看4.1.3節。

2.6.1       常見問題

1)       如何通過拖放調整行的順序?

3          列/單元格類型揭密(column/cell types)

DataGridView控件提供了幾種列類型用以顯示資料,并允許使用者修改和添加資料。

當你對DataGridView進行了綁定,并将它的AutoGenerateColumns屬性設定為true,它會根據資料源中列的資料類型自動生成列,這些列都使用相應的預設類型(與資料源列資料類型相适應)。

你也可以自行建立列的執行個體,将它們加入DataGridView的Columns集合中,這些列可用作非綁定列,也可以以手動方式讓它們用于綁定資料。手動綁定的列非常有用,比如,自動生成的列都采用與資料源的列相應的預設類型,而你不想用預設列類型。

下表描述了DataGridView 的各種列對應的類:

列類型 描述
DataGridViewTextBoxColumn 用于基于文本的值。綁定到數字和字元串值時會自動生成這種類型的列。
DataGridViewCheckBoxColumn 用于顯示Boolean和CheckState類型的值,綁定到上述類型值時會自動生成這種類型的列。
DataGridViewImageColumn 用于顯示圖像。綁定到byte數組,Image對象,圖示對象時會自動生成這種類型的列。
DataGridViewButtonColumn 用于在單元格内顯示按鈕。在綁定時不會自動生成,一般用于非綁定列。
DataGridViewComboBoxColumn 用于在單元格内顯示下拉清單。在綁定時不會自動生成,一般地需要手工綁定。
DataGridViewLinkColumn 用于在單元格内顯示連結。在綁定時不會自動生成,一般地需要手工綁定。
自定義列類型 通過繼承DataGridViewColumn 類或其子類,你可以建立自己的列類型,以提供自定義的外觀、行為和宿主要件。

常見問題(FAQ)

1)       如何隐藏一列?

2)       如何使特定的單元格不可編輯?

3)       如何避免使用者将焦點設定到指定的單元格?

4)     如何調整最後一列的寬度使其占據網格的剩餘客戶區?

3.1       DataGridViewTextBoxColumn

DataGridViewTextBoxColumn是一種通用的列類型,用于表示基于文本的值,比如數字和字元串。在編輯模式下,會有一個TextBox控件出現在目前活動單元格,使用者可以修改單元格的值。

單元格的值在顯示時會自動轉換為字元串。使用者輸入或修改的值在送出時則被自動解析為合适的資料類型以建立一個單元格的值。通過處理CellFoamatting和CellParsing事件,你可以自定義這些轉換的方式。比如将資料源的日期字段以特定的形式顯示,對某些特殊單元格作出特殊的标記。

對一列來說,它包含的單元格值的資料類型由該列的ValueType屬性指定。

3.1.1       常見問題

1)     如何讓TextBox類型的單元格支援換行?

2)       Why does the cell text show up with “square” characters where they should be new lines?

3)       如何在單元格内同時顯示圖示和文本?

4)       如何避免使用者将焦點設定到指定的單元格?

3.2       DataGridViewCheckBoxColumn

DataGridViewCheckBoxColumn用于顯示Boolean或CheckState類型的值。Boolean 值顯示為二進制(two-state)或三元 (three-state) 的CheckBox,而這取決于該列的ThreeState 屬性的值。如果該類型的列綁定到CheckState類型的值,ThreeState屬性的預設值為true。

一般情況下,CheckBox類型的單元格要麼用于存儲資料,就像其它類型的資料一樣,要麼用于進行一些重要操作。使用者點選CheckBox單元格時,如果你希望對此立即做出反應,可以處理CellClick事件,但該事件發生在單元格的值更新之前。如果點選之時就希望獲得新值,一種選擇是根據目前值計算點選後的值;另一種方法是立即送出值的變化,然後在CellValueChanged事件處理函數中對此作出反應,而要在使用者點選單元格時立即送出值的變化,你必須處理CurrentCellDirtyStateChanged事件,在這裡,調用CommitEnd方法送出新值。

3.3       DataGridViewImageColumn

DataGridViewImageColumn 類型的列用于顯示圖像。這種類型的列有三種方法生成:綁定到資料源時自動生成;為非綁定列手動生成;在CellFormatting事件處理函數(該事件發生在單元格顯示前)中動态生成。

綁定到資料源時自動生成Image列的方法适用于大量的圖像格式,包括.NET中Image類支援的各種格式,還有Access資料庫及Northwind範例資料庫使用的OLE圖檔格式。

如果你想提供DataGridViewButtonColumn列的功能,又希望顯示自定義的外觀,手動生成Image列會很有用。在顯示後,你可以處理CellClick事件以處理使用者對單元格的點選(模拟按鈕列)。

如果你要為計算值或非圖檔的值提供圖檔顯示,在CellFormatting事件處理函數中動态生成Image列的方法會很有用。比如,你有一個表示風險值的列,它的值可能是”high”、”middle”或”low”,可以為它們顯示不同的圖示作為警示;或者你有一個名為”Image”的列,它的值時圖檔檔案的位置而不是真實的圖檔内容,也可以用這種方法。

3.3.1       常見問題

1)     如何使Image列不顯示任何圖像(字段值為null時)?

3.4       DataGridViewButtonColumn

使用DataGridViewButtonColumn 列,可以在單元格内顯示按鈕。如果你要為使用者操作特定行提供一種簡單的方式,Button列會很有用,比如排序或在另一個窗體中顯示子表記錄。

在對DataGridView進行資料綁定時不會自動生成Button列,是以你必須手動建立它們,然後把它們添加到DataGridView控件的Columns集合中。

你可以處理CellClick事件以響應使用者的點選動作。

3.5       DataGridViewComboBoxColumn

在DataGridViewComboBoxColumn類型的列中,你可以顯示包含下拉清單的單元格。這在僅允許使用者輸入一些特定值的時候顯得很有用,比如在SQL Server示例資料庫Northwind中Products表的Category列,它表示産品的種類,這個應隻允許選擇現有的産品種類,此時就可以使用ComboBox列。

如果你了解如何為ComboBox控件生成下拉清單,就可以用相同的方式為ComboBox列中的所有單元格生成下拉清單。要麼通過列的Items集合手動添加,要麼通過DataSource,DisplayMember 和ValueMember屬性綁定到一個資料源。要了解其中的更多資訊,可以參考WinForms中ComboBox空間的用法。

你可以将ComboBox列的單元格的實際值綁定到DataGridView控件本身的資料源(注意不是ComboBox列的資料源),這需要設定該列的DataPropertyName屬性(設定某個列的名稱)。

ComboBox列不會在資料綁定時自動生成,是以你必須手動建立它們,然後将其添加到Columns集合屬性中。另外,你也可以使用設計器,在設計時設定相應的屬性,這個過程類似于在設計器中ComboBox控件的使用。

3.5.1       DataError事件和ComboBox列

在使用DataGridViewComboBoxColumn 時,有時會修改單元格的值或啟動ComboBox控件的Items集合,這樣可能會引發DataError事件。這是ComboBox列的設計使然,ComboBox列的單元格會進行資料驗證。在ComboBox列的單元格嘗試繪制包含的内容時,它需要将包含的值進行格式化(見第二章第三節),在此轉換過程中,它會在ComboBox的Items集合中查找對應的值,如果查找失敗,就會引發DataError事件。忽略了DataError事件可能會使單元格不能進行正确的格式化。

3.5.2       常見問題

1)     如何能夠在ComboBox類型的單元格中輸入資料?

2)     How do I handle the SelectedIndexChanged event?

3)     How do I have a combo box column display a sub set of data based upon the value of a different combo box column?

3.6       DataGridViewLinkColumn

使用DataGridViewLinkColumn列,你可以顯示一列包含超連結的單元格。在顯示資料源中的URL值,或者替代按鈕列進行一些特殊行為,如打開另一個子記錄窗體時會很有用。

Link列也不會在DataGridView資料綁定時自動生成。要使用它,你還得手動建立,然後将它添加到DataGridView控件的Columns集合中。

你可以處理CellContentClick事件來相應使用者的點選動作。這個事件不同于CellClick 和CellMouseClick 事件,後兩者在使用者點選單元格任何位置(而不僅僅時連結)時都會觸發。

DataGridViewLinkColumn 類提供了幾個屬性,用來修改連結的外觀,包括點選前,點選時和點選後(類似于網頁中的超連結)。

4          操作資料(Working with Data)

多數情況下,使用DataGridView的時候都需要跟資料打交道,這時有很多事情可能需要你去做。你需要驗證使用者輸入的資料,或者需要對資料進行格式化。DataGridView能夠以三種模式顯示資料:bound、unboundand 和virtual。每種模式都有自己的特性和存在的理由。不管是否是資料綁定模式,在操作資料時,如果發生錯誤,DataGridView通常會觸發DataError事件,了解該事件發生的原因能讓你更好地利用它。

4.1       資料輸入和驗證的相關事件

使用者輸入資料時-對其所在的行或單元格,你可能希望驗證這些資料,在遇到無效資料時通知使用者。就像常見的Windows Forms控件,DataGridView的行和單元格也有Validating和Validated事件,驗證事件可被取消。使用者在單元格/行間移動時會觸發Enter和Leave事件。最後,使用者在開始編輯單元格時也會觸發事件。了解所有這些程式的發生順序會對你很有幫助。

4.1.1       資料驗證相關事件的順序

下面列出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 (新的單元格)

4.1.2       驗證資料

驗證使用者輸入時,如果DataGridView采用非資料綁定模式,通常會對單元格進行驗證;而如果采用資料綁定模式,則一般會對行進行驗證。這與資料的組織方式密切相關,非資料綁定模式下,一行的單元格間關系一般比較“散”,而綁定模式下,資料源的資料一般以行來組織。但有時在資料綁定模式下會同時進行單元格級和行級的驗證。

4.1.2.1      顯示錯誤資訊

一旦遭遇了無效的輸入資料,你通常需要通知使用者。這時有多種方式可以選擇,傳統的方式是使用資訊對話框。DataGridView還能夠為行或單元格顯示一個錯誤圖示來通知使用者輸入了無效資料。錯誤圖示帶有一個工具提示,它提供了該錯誤的相關資訊:

4.1.2.2      常見問題(FAQ)

1)     如何在使用者編輯單元格的時候顯示錯誤圖示?

4.1.3       在新行中的資料輸入(Data Entry in the New Row)

當在程式中使用DataGridView來編輯資料時,你往往希望提供讓使用者添加新行資料的功能。DataGridView控件支援這個功能,提供了一個用于添加新記錄的行,而這一行總是顯示為最後一行,并在該行的标題單元格标以星号(*)。 下面的幾個小節會讨論一些在程式中使用這個新行時需要考慮的内容。(下面總是以 新行 表示 用于添加新記錄的行 )

4.1.3.1     顯示新行

使用AllowUserToAddRows屬性以訓示是否顯示新行,其預設值為true。

新行處于網格的最後一行,标題帶有星号:

在資料綁定的情況下,當DataGridView控件的AllowUserToAddRows屬性和資料源的IBindingList.AllowNew 屬性都為true時,新行才會顯示,隻要兩者有一個為false,新行就不會顯示。

4.1.3.2     為生成的新行添加預設值

當使用者選擇新行作為目前行,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();

}

4.1.3.3     Rows集合與新行的關系

新行包含在DataGridView控件的Rows集合中,又因其總是處于最後一行,下面這行代碼會傳回新行:

DataGridViewRow row = dataGridView1.Rows[dataGridView1.Rows.Count - 1];

盡管新行也包含在Rows集合中,它與Rows集合中其它行的行為卻不相同,表現在兩點:

  • 不能以程式設計的方式将新行從Rows集合中移除,如果你嘗試這麼做,會抛出InvalidOperationException類型的異常。使用者也不能删除新行。DataGridViewRowCollection.Clear()方法也不能将新行從Rows集合中移除。
  • 不能在新行之後添加行。如果你嘗試這麼做,會抛出InvalidOperationException 類型的異常。這種特性的結果是,新行總處于DataGridView的最後一行。當新行顯示的時候,DataGridViewRowCollection 類中用于添加行的方法-Add,AddCopy以及AddCopies-在内部都調用用于插入的方法。

4.1.3.4     在新行中輸入資料

使用者開始在新行輸入資料之前,新行的IsNewRow屬性值為true;一旦使用者開始輸入,這一行就不再是新行了,DataGridView中會産生一個“新”的新行,看下面示意圖:

在添加“新”的新行時,會觸發UserAddedRow事件,它的事件處理函數的第二個參數有屬性Row,指定了這個“新”的新行。如果使用者此時按下Escape鍵,“新”的新行會被移除,這會觸發UserDeletingRow事件,它的事件處理函數的第二個參數的屬性Row指定了“新”的新行。

4.1.3.5     自定義新行的可視化效果

新行是基于RowTemplate模闆建立的,如果沒有指定它的單元格的樣式,它們會采用繼承的樣式。要了解樣式繼承的更多資訊,請參看第五章第一節的内容。

新行中單元格的初始值是由每個單元格的DefaultNewRowValue屬性決定的。對于DataGridViewImageCell類型的單元格,其初始值為一個占位圖檔,其它類型的則為null。你可以重寫這個屬性以傳回自定義值。但也可以在DefaultValuesNeeded事件處理函數中對預設值進行替換,該事件在焦點進入新行時觸發。

新行标題的标準圖示是箭頭或者星号,并沒有得到暴露。如果你要自定義這個圖示,就需要建立一個自定義的DataGridViewRowHeaderCell 類。

新行的标題的标準圖示使用标題單元格DataGridViewCellStyle的ForeColor屬性。注意:如果沒有足夠的空間,圖示就不會再顯示。

如果為标題單元格設定了字元串值(通過Value屬性),但沒有足夠的控件同時顯示文本和圖示,那麼圖示會被首先截掉。

4.1.3.6     新行的排序

在非綁定模式下,新行總是添加在DataGridView的最後一行,即使已經對資料排序。使用者需要在添加新行後再次進行排序,以将新記錄放在合适的位置;這種行為方式類似于ListView控件。

在綁定模式或虛拟模式(Virtual Mode)下,如果已對資料排序,那麼插入資料時的行為取決于資料模型的實作方式。對于ADO.NET,新加的行會被自動排序至合适的位置。

4.1.3.7     關于新行,還要注意:

你不能将新行的Visible屬性值設定為false,否則會觸發一個InvalidOperationException類型的異常。

新行在建立時總是處于非選中(unselected)狀态。

4.1.3.8     Virtual Mode下的新行

如果你正要實作虛拟模式(Virtual Mode),需要考慮資料模型添加新行和復原添加操作的情況。該功能準确的實作方式取決于資料模型的實作方式及其事務機制,例如,送出的時候是針對單元格還是行。參看本文檔後面關于Virtual Mode的主題。

4.2       關于Null值

在使用資料源的時候,比如資料庫或業務對象,經常需要處理null值。null值可能是一個實際的null(VB中為Nothing),也可能是一個資料庫的”null”值(DBNull.Value),當你遭遇了這些值,就需要考慮如何顯示它們。另一方面,很多時候,你還需要向資料源寫入null值。使用單元格Style的NullValue屬性和DataSourceNullValue 屬性,你可以改變DataGridView處理null值的方式。

4.2.1       NullValue屬性

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屬性以了解究竟是輸入了什麼作為單元格的值。

4.2.2       DataSourceNullValue屬性

DataGridViewCellStyle.DataSourceNullValue屬性要被命名為ParseNullValue的,如果NullValue屬性被命名為FormattedNullValue的話,但最後還是采用了DataSourceNullValue,這樣更直覺準确。在将null值寫入單元格的值時,就會用到DataSourceNullValue屬性。在資料綁定情形下,這個null值将被寫入資料庫或業務對象,此處需要進行控制,因為對于資料庫和業務對象來說,null的概念不盡相同。通常你會期望,使用業務對象時将DataSourceNullValue 設定為null,而使用資料庫時則将其設定為DBNullValue。DataSourceNullValue的預設值為DBNull.Value。

4.3       DataError事件

将DataError事件獨立出來作為一個主題,是因為在操作資料時,經常會遭遇DataError事件。在操作資料時,DataError主要發生在一下情況:不能讀/寫或轉換單元格的資料;在嘗試進行某種編輯操作時發生了異常。

編輯操作中的DataError 事件

下面的清單列出了可能會引發DataError事件的編輯操作:

  • 取消編輯(Canceling an edit)
  • 重新整理一個編輯 (通過調用RefreshEdit方法)
  • 嘗試将單元格的值寫入資料源
  • 初始化編輯控件\單元格的值(通過設定單元格的FormattedValue屬性或調用單元格的InitializeEditingControl方法)
  • 結束編輯(Ending an edit)
  • 送出編輯(Committing an edit)
  • 删除一行(Deleting a row)

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

usually also requires getting the cell's formatted value also.

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.

4.4       資料綁定模式(Databound modes)

4.4.1       非綁定模式(Unbound Mode)

如果你要在程式中管理數量相對較小的資料,那麼非綁定模式會比較合适。此時你不是像綁定模式中那樣将DataGridView控件直接指向一個資料源,而是手動去生成控件。一般需要用到DataGridViewRowCollection.Add 方法(該方法向DGV中添加行)。

非綁定模式在處理靜态、隻讀的資料時特别有用,也可以用在以自己的方式與外部資料源互動的情況,但實際上,如果你希望你的使用者與外部的資料源互動,一般還是用綁定模式(bound mode)更好。

4.4.2       綁定模式(Bound Mode)

如果你在程式中管理一些資料,并希望能與資料源自動進行互動,就應該使用綁定模式。此時你可以設定DataSource屬性,将資料源綁定到DataGridView控件。如果控件使用了綁定模式,就不需要你去顯式地對資料進行讀寫了。如果AutoGenerateColumns 屬性為true,資料源中的每一列都會在DataGridView中生成一個相應的列(根據列的資料類型),如果你希望建立自己的列,可以将該屬性設定為false,使用DataPropertyName屬性将一列綁定到資料源的一列,這在你不想用自動生成的列類型時很有用。

4.4.2.1      有效的資料源

将資料綁定到DataGridView非常簡單、直覺,很多情況下,你隻需要設定它的DataSource屬性。如果使用的資料源包含多個清單(list)或資料表(table),你還需要設定控件的DataMember屬性,該屬性為字元串類型,用于指定要綁定的清單或資料表。

DataGridView控件支援标準的WinForm資料綁定模型,是以它可以綁定到下面清單中的類的執行個體:

  • 任意實作了IList接口的類,包括一維數組;
  • 任意實作了IListSource接口的類,比如DataTable和DataSet;
  • 任意實作了IBindingList 接口的類,比如BindingList ;
  • 任意實作了IBindingListView接口的類,比如BindingSource 。

清單更改通知(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 ,那就不用再額外實作更改通知了。

4.4.3       虛拟模式

使用虛拟模式,你可以實作自己的資料管理操作。在綁定模式下,如果要使用非綁定列,那麼要想在對列排序時能夠維護非綁定列的值,就需要虛拟模式。但虛拟模式的最主要的用途還是在操作大量資料時優化性能。

你将DataGridView綁定到緩存的資料,然後用代碼控制資料行的存取。要保持使用記憶體量比較小,緩存的資料量應與目前要顯示的行數相當。當使用者滾動控件看到了新的行時,你的代碼就從緩存中請求新的資料,并從記憶體中清除舊的資料。

如果你正要實作虛拟模式(Virtual Mode),需要考慮資料模型添加新行和復原添加操作的情況。該功能準确的實作方式取決于資料模型的實作方式及其事務機制,例如,送出的時候是針對單元格還是行。參看本文檔後面關于Virtual Mode的主題。

4.4.4       混合模式 – 綁定與非綁定模式

顯示在DataGridView中的資料通常來自于某種類型的資料源,但是你可能也希望顯示一個資料源之外的列。這種列稱為非綁定列。

你可以在綁定模式下添加非綁定列,在你希望顯示一個按鈕列或者連結列讓使用者操作一些特定行時這顯得很有用,另外也可以用非綁定列顯示一些由綁定列計算而得到的值。你可以在CellFormatting事件處理函數中生成計算列的值。不過如果你使用的資料源是DataSet或DataTable,你可能希望使用DataColumn.Expression 屬性來建立一個計算列,在這種情況下,在DGV看來,這一列就跟資料源中其它列是一樣的。

在綁定模式下根據非綁定列排序是不受支援的。如果你在綁定模式下建立了非綁定列,你必須實作虛拟模式,這樣在根據綁定列排序時可以維護非綁定列的值。

如果添加的非綁定列不能由資料源資料計算得來或者這些資料會頻繁更新,你就應該使用虛拟模式。要了解虛拟模式的更多資訊,請參看本文檔後面的虛拟模式相關章節。

4.4.5       常見問題

1)     如何同時顯示綁定資料和非綁定資料?

2)     How do I show data that comes from two tables?(TODO)

3)     如何顯示主從表?

4)     如何在同一DataGridView内顯示主從表?

5)     如何避免對一列的排序?

6)     如何針對多個列排序?

7)     How do I have a combo box column display a sub set of data based upon the value of a different combo box column?(TODO)

8)     如何在點選工具欄按鈕的時候将資料送出到資料庫?

9)     如何在使用者删除記錄時顯示确認對話框?

5          特性綜覽(Overview of features)

5.1       樣式(Styling)

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.

5.1.1       The DataGridViewCellStyle Class

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,對齊,填充

5.1.2       Using DataGridViewCellStyle Objects

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.

5.1.3       Style Inheritance

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.

  1. DataGridViewCell.Style
  2. DataGridViewRow.DefaultCellStyle
  3. AlternatingRowsDefaultCellStyle (only for cells in rows with odd index numbers)
  4. RowsDefaultCellStyle
  5. DataGridViewColumn.DefaultCellStyle
  6. DefaultCellStyle

For row and column header cells, the InheritedStyle property is populated by values from the following list of source properties in the given order.

  1. DataGridViewCell.Style
  2. ColumnHeadersDefaultCellStyle or RowHeadersDefaultCellStyle
  3. DefaultCellStyle

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.

  1. DataGridViewColumn.DefaultCellStyle
  2. DefaultCellStyle

The row InheritedStyle property inherits its values from the following properties.

  1. DataGridViewRow.DefaultCellStyle
  2. AlternatingRowsDefaultCellStyle (only for cells in rows with odd index numbers)
  3. RowsDefaultCellStyle
  4. DefaultCellStyle

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.

5.1.4       Setting Styles Dynamically

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.

5.2       Custom painting

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.

5.2.1       Paint Parts

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

5.2.2       Row Pre Paint and Post Paint

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

5.3       Autosizing

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.

常見問題:

1)     如何調整最後一列的寬度使其占據網格的剩餘客戶區?

5.3.1       Sizing Options in the Windows Forms DataGridView Control 

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.

5.3.2       Resizing with the Mouse

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:

  • AllowUserToResizeColumns
  • AllowUserToResizeRows
  • ColumnHeadersHeightSizeMode
  • RowHeadersWidthSizeMode

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.

5.3.3       Automatic Sizing

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:

  • ColumnHeadersHeightSizeMode
  • RowHeadersWidthSizeMode
  • AutoSizeColumnsMode
  • AutoSizeRowsMode

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.

5.3.4       Programmatic Resizing

When automatic sizing is disabled, you can programmatically set the exact width or height of rows, columns, or headers through the following properties:

  • RowHeadersWidth
  • ColumnHeadersHeight
  • DataGridViewRow.Height
  • DataGridViewColumn.Width

You can also programmatically resize rows, columns, and headers to fit their contents using the following methods:

  • AutoResizeColumn
  • AutoResizeColumns
  • AutoResizeColumnHeadersHeight
  • AutoResizeRow
  • AutoResizeRows
  • AutoResizeRowHeadersWidth

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.

5.3.5       Customizing Content-based Sizing Behavior

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.

5.3.6       Content-based Sizing Options

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.

5.4       Selection modes

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.

5.4.1       Programmatic Selection

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。

5.5       滾動(Scrolling)

DataGridView毫無疑問地會提供對水準和垂直滾動條的支援,它同時也支援使用滑鼠滾輪進行垂直滾動。水準方向的滾動基于像素值,而垂直方向的滾動則基于行的索引,DataGridView不支援垂直方向的基于像素值的滾動。

5.5.1       Scroll event

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.

5.5.2       Scroll bars

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.

5.5.3       Scrolling Properties

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.

5.6       Sorting

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.

5.6.1       Programmatic Sorting

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.

5.6.2       Custom Sorting

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.

5.6.3       Common questions and scenarios

1)     如何避免使用者對列排序?

2)     如何針對多個列排序?

5.7       Border styles

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.

5.7.1       Standard Border Styles

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.

5.7.2       Advanced Border Styles

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

5.8       Enter-Edit modes

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:

  • The underlying data source supports editing.
  • The DataGridView control is enabled.
  • The EditMode property value is not EditProgrammatically.
  • The ReadOnly properties of the cell, row, column, and control are all set to false.

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.

5.9       Clipboard copy modes

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.

5.10    Frozen columns/rows

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.

5.11    Implementing Custom cells and editing controls/cells

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.

5.11.1    IDataGridViewEditingControl

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.

5.11.2    IDataGridViewEditingCell

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.

5.12    Virtual mode

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.

5.12.1    Bound Mode and Virtual Mode

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.

5.12.2    Supplementing Bound Mode

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.

5.12.3    Common questions and scenarios

1)     How do I show unbound data along with bound data?

2)     How do I show data that comes from two tables?

5.12.4    Replacing Bound Mode

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.

5.12.5    Virtual-Mode Events

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.

5.12.6    Best Practices in Virtual Mode

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

5.13    容量(Capacity)

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.

6          最佳實踐(Best Practices)

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).

6.1       Using Cell Styles Efficiently

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:

  • Avoid setting cell style properties for individual DataGridViewCell or DataGridViewRow objects. This includes the row object specified by the RowTemplate property. Each new row that is cloned from the row template will receive its own copy of the template's cell style object. For maximum scalability, set cell style properties at the DataGridView level. For example, set the DefaultCellStyle property rather than the DataGridViewCell.Style property.
  • If some cells require formatting other than default formatting, use the same DataGridViewCellStyle instance across groups of cells, rows, or columns. Avoid directly setting properties of type DataGridViewCellStyle on individual cells, rows, and columns. For an example of cell style sharing, see How to: Set Default Cell Styles for the Windows Forms DataGridView Control. You can also avoid a performance penalty when setting cell styles individually by handling the CellFormatting event handler. For an example, see How to: Customize Data Formatting in the Windows Forms DataGridView Control.
  • When determining a cell's style, use the DataGridViewCell.InheritedStyle property rather than the DataGridViewCell.Style property. Accessing the Style property creates a new instance of the DataGridViewCellStyle class if the property has not already been used. Additionally, this object might not contain the complete style information for the cell if some styles are inherited from the row, column, or control. For more information about cell style inheritance, see Cell Styles in the Windows Forms DataGridView Control.

6.2       Using Shortcut Menus Efficiently

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:

  • Avoid creating shortcut menus for individual cells and rows. This includes the row template, which is cloned along with its shortcut menu when new rows are added to the control. For maximum scalability, use only the control's ContextMenuStrip property to specify a single shortcut menu for the entire control.
  • If you require multiple shortcut menus for multiple rows or cells, handle the CellContextMenuStripNeeded or RowContextMenuStripNeeded events. These events let you manage the shortcut menu objects yourself, allowing you to tune performance.

6.3       Using Automatic Resizing Efficiently

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:

  • Avoid using automatic sizing on a DataGridView control with a large set of rows. If you do use automatic sizing, only resize based on the displayed rows. Use only the displayed rows in virtual mode as well.
  • For rows and columns, use the DisplayedCells or DisplayedCellsExceptHeaders field of the DataGridViewAutoSizeRowsMode, DataGridViewAutoSizeColumnsMode, and DataGridViewAutoSizeColumnMode enumerations.
  • For row headers, use the AutoSizeToDisplayedHeaders or AutoSizeToFirstHeader field of the DataGridViewRowHeadersWidthSizeMode enumeration.
  • For maximum scalability, turn off automatic sizing and use programmatic resizing.

6.4       Using the Selected Cells, Rows, and Columns Collections Efficiently

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:

  • To determine whether all the cells in the DataGridView have been selected before you access the contents of the SelectedCells collection, check the return value of the AreAllCellsSelected method. Note, however, that this method can cause rows to become unshared. For more information, see the next section.
  • Avoid using the Count property of the DataGridViewSelectedCellCollection to determine the number of selected cells. Instead, use the GetCellCount() method and pass in the DataGridViewElementStates.Selected value. Similarly, use the DataGridViewRowCollection.GetRowCount() and DataGridViewColumnCollection.GetColumnCount() methods to determine the number of selected elements, rather than accessing the selected row and column collections.
  • Avoid cell-based selection modes. Instead, set the SelectionMode property to FullRowSelect or FullColumnSelect.

6.5       Using Shared Rows

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:

  • The row contains a single selected cell that is not in a selected column.
  • The row contains a cell with its ToolTipText or ContextMenuStrip properties set.
  • The row contains a DataGridViewComboBoxCell with its Items property set.

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:

  • Avoid calling the Add(Object[]) overload of the Add method and the Insert(Object[]) overload of the Insert method of the Rows collection. These overloads automatically create unshared rows.
  • Be sure that the row specified in the RowTemplate property can be shared in the following cases:
  • When calling the Add() or Add(Int) overloads of the Add method or the Insert(Int, Int) overload of the Insert method of the Rows collection.
  • When increasing the value of the RowCount property.
  • When setting the DataSource property.
  • Be sure that the row indicated by the indexSource parameter can be shared when calling the AddCopy, AddCopies, InsertCopy, and InsertCopies methods of the Rows collection.
  • Be sure that the specified row or rows can be shared when calling the Add(DataGridViewRow) overload of the Add method, the AddRange method, the Insert(Int32,DataGridViewRow) overload of the Insert method, and the InsertRange method of the Rows collection.

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.

6.6       Preventing Rows from Becoming Unshared

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:

  • Avoid indexing the Rows collection or iterating through it with a foreach loop. You will not typically need to access rows directly. DataGridView methods that operate on rows take row index arguments rather than row instances. Additionally, handlers for row-related events receive event argument objects with row properties that you can use to manipulate rows without causing them to become unshared.
  • If you need to access a row object, use the DataGridViewRowCollection.SharedRow(Int) method and pass in the row's actual index. Note, however, that modifying a shared row object retrieved through this method will modify all the rows that share this object. The row for new records is not shared with other rows, however, so it will not be affected when you modify any other row. Note also that different rows represented by a shared row may have different shortcut menus. To retrieve the correct shortcut menu from a shared row instance, use the GetContextMenuStrip method and pass in the row's actual index. If you access the shared row's ContextMenuStrip property instead, it will use the shared row index of -1 and will not retrieve the correct shortcut menu.
  • Avoid indexing the DataGridViewRow.Cells collection. Accessing a cell directly will cause its parent row to become unshared, instantiating a new DataGridViewRow. Handlers for cell-related events receive event argument objects with cell properties that you can use to manipulate cells without causing rows to become unshared. You can also use the CurrentCellAddress property to retrieve the row and column indexes of the current cell without accessing the cell directly.
  • Avoid cell-based selection modes. These modes cause rows to become unshared. Instead, set the SelectionMode property to DataGridViewSelectionMode.FullRowSelect or DataGridViewSelectionMode.FullColumnSelect.
  • Do not handle the DataGridViewRowCollection.CollectionChanged or RowStateChanged events. These events cause rows to become unshared. Also, do not call the DataGridViewRowCollection.OnCollectionChanged(CollectionChangeEventArgs) or OnRowStateChanged(Int,DataGridViewRowStateChangedEventArgs) methods, which raise these events.
  • Do not access the SelectedCells collection when the SelectionMode property value is FullColumnSelect, ColumnHeaderSelect, FullRowSelect, or RowHeaderSelect. This causes all selected rows to become unshared.
  • Do not call the AreAllCellsSelected(boolean) method. This method can cause rows to become unshared.
  • Do not call the SelectAll method when the SelectionMode property value is CellSelect. This causes all rows to become unshared.
  • Do not set the ReadOnly or Selected property of a cell to false when the corresponding property in its column is set to true. This causes all rows to become unshared.
  • Do not access the DataGridViewRowCollection.List property. This causes all rows to become unshared.
  • Do not call the Sort(IComparer) overload of the Sort method. Sorting with a custom comparer causes all rows to become unshared.

你可以檢索各種屬性的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

•AutoSizeRowsMo​​de

若要重寫控件的列大小的單個列模式,将其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(DataGridViewAutoSizeRowsMo​​de,布爾)的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的滾動條可以通路,它通過保護Horizo​​ntalScrollBar和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單值單,SingleHorizo​​ntal和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鍵,進入跨越行值,或當按下Enter鍵,進入下一個列值。

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控制自動調整大小。如果你使用自動大小調整,隻調整的基礎上所顯示的行。在虛拟模式下隻使用所顯示的行以及。

對行和列•,使用DataGridViewAutoSizeRowsMo​​de,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接口)超載。一個自定義比較排序會導緻所有行成為非共享。

附錄 A – FAQ

該附錄包含的代碼示例和片段集中解答了前面散落的常見問題:

1.   如何使指定的單元格不可編輯?

ReadOnly屬性決定了單元格中的資料是否可以編輯,可以設定單元格的ReadOnly 屬性,也可以設定DataGridViewRow.ReadOnly 或DataGridViewColumn.ReadOnly使得一行或一列所包含的單元格都是隻讀的。 預設情況下,如果一行或一列是隻讀的,那麼其包含的單元格也會使隻讀的。

不過你仍可以操作一個隻讀的單元格,比如選中它,将其設定為目前單元格,但使用者不能修改單元格的内容。注意,即使單元格通過ReadOnly屬性設定為隻讀,仍然可以通過程式設計的方式修改它,另外ReadOnly也不會影響使用者是否可以删除行。

2.   如何讓一個單元格不可用(disable)?

單元格可以設定為隻讀而不可編輯,但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);

        }

    }

}

3.   如何避免使用者将焦點設定到指定的單元格?

預設情況下DataGridView的操作(navigation)模型在限制使用者将焦點置于指定的單元格方面沒有提供任何支援。你可以實作自己的操作邏輯,這需要重寫合适的鍵盤、導航、滑鼠方法,如DataGridView.OnKeyDown, DataGridView.ProcessDataGridViewKey, DataGridView.SetCurrentCellAddressCore,  DataGridView.SetSelectedCellCore, DataGridView.OnMouseDown。

4.   如何使所有單元格總是顯示控件(不論它是否處于編輯狀态)?

DataGridView 控件隻支援在單元格處于編輯狀态時顯示真實的控件(如TextBox)。DataGridView 沒有被設計為顯示多控件或為每行重複顯示控件。DataGridView 在單元格不被編輯時為其繪制對應控件的外觀,該外觀可能是你想要的。例如,DataGridViewButtonCell 類型的單元格,不管它是否處于編輯狀态,總是表現為一個按鈕。

5.   Why does the cell text show up with “square” characters where they should be new lines(TODO,未能實作該效果)?

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.

6.   如何在單元格内同時顯示圖示和文本?

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; }

        }

    }

7.   如何隐藏一列?

有時希望僅顯示DataGridView的部分列,将其它列隐藏。比如DataGridView含有一列包含員工薪水資訊,你可能希望僅将這些資訊顯示給具有一定信用級别的人,其他人則隐藏。

通過程式設計方式隐藏

DataGridViewColumn類的Visible 屬性決定了是否顯示該列。

通過設計器隐藏

1)     右擊DataGridView控件,選擇Edit Columns;

2)     在列清單中選擇一列;

3)     在列屬性網格中,将Visible屬性設定為false。

8.   如何避免使用者對列排序?

對于DataGridView 控件,預設情況下,TextBox類型的列會自動排序,而其它類型的列則不會自動排序。這種自動排序有時會把資料變得比較亂,這時你會想更改這些預設設定。

DataGridViewColumn的屬性SortMode決定了列的排序方式,将其設定為DataGridViewColumnSortMode.NotSortable就可以避免預設的排序行為。

9.   如何針對多個列排序?

預設情況下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 void Main()

    {

        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 void Main()

    {

        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;

        }

    }

}

10. 如何為編輯控件添加事件處理函數?

有時候你需要處理單元格包含的編輯控件的特定事件。你需要處理DataGridView.EditingControlShowing 事件,它的第二個參數的Control屬性能讓你通路該單元格包含的編輯控件。如果你要處理的事件不屬于它的基類Control,還需要将該控件轉換為特定的控件(一般為ComboBox控件或TextBox控件)。

注意:如果類型相同,DataGridView會重用該編輯控件,是以,你應該確定不會添加已存在的事件處理函數,否則會調用相同的函數多次(可以在添加前先将其移除,請參考我的示例代碼)。

11. 應在何時移除編輯控件的事件處理函數?

如果你隻是想臨時為編輯控件添加事件處理函數(可能是針對特定列的特定單元格),你可以在CellEndEdit事件中移除該處理函數。你也可以在添加之前移除任何已存在的事件處理函數。

12. 如何處理ComboBox列中控件的SelectIndexChanged事件?

有時知道使用者何時選擇了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");

}

13. 如何通過拖放調整行的順序?

通過拖放調整行的順序不是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);

    }

}

14. 如何調整最後一列的寬度使其占據網格的剩餘客戶區?

以預設方式填充DataGridView時,可能會發生因列的寬度不夠,而暴露出控件的灰色背景的情況,很不美觀。将最後一列的AutoSizeMode屬性設定為Fill會使該列調整大小來填充網格的剩餘客戶區(client area)。作為一個可選的方式,你可以設定最後一列MinimumWidth屬性,以保持該列的寬度不至于太小。

15. 如何讓TextBox類型的單元格支援換行?

預設情況下,DataGridViewTextBoxCell不支援換行,這個可以由DataGridViewCellStyle的WrapMode屬性來控制。 (如DataGridView.DefaultCellStyle.WrapMode)。将WrapMode 屬性DataGridViewTriState枚舉的三個取值之一。

下面的代碼示例使用DataGridView.DefaultCellStyle屬性設定整個控件所包含的單元格的WrapMode屬性(即設定所有單元格的換行模式)。

this.dataGridView1.DefaultCellStyle.WrapMode = DataGridViewTriState.True;

16. 如何使Image列不顯示任何圖像(字段值為null時)?

預設情況下Image類型的列和單元格将null值轉換為标準的“X”圖像( ),将Image列的NullValue屬性設定為null可使該列不顯示任何圖像。下面這行代碼示範了如何設定Image列的NullValue屬性。

this.dataGridViewImageColumn1.DefaultCellStyle.NullValue = null;

17. 如何能夠在ComboBox類型的單元格中輸入資料?

預設情況下,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;

         }

    }

}

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(TODO)?

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();

    }

}

19. 如何在使用者編輯控件的時候(而不是在驗證時)就顯示錯誤圖示?

在使用錯誤文本和圖示時,有時你希望為使用者提供一個即時回報,以提示目前的輸入不正确。預設情況下,即使設定了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;

        }

    }

}

20. 如何同時顯示綁定資料和非綁定資料?

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;

    }

}

21. How do I show data that comes from two tables(TODO)?

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.

22. 如何顯示主從表?

使用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 void Main()

    {

        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.");

        }

    }

}

23. 如何在同一DataGridView中顯示主從表?

DataGridView 不支援在同一DataGridView 中顯示主從表。Windows Forms的先前版本中的DataGrid控件或許是你需要的一個解決方案。

24. 如何避免使用者對列排序?

對于DataGridView 控件,預設情況下,TextBox類型的列會自動排序,而其它類型的列則不會自動排序。這種自動排序有時會把資料變得比較亂,這時你會想更改這些預設設定。

DataGridViewColumn的屬性SortMode決定了列的排序方式,将其設定為DataGridViewColumnSortMode.NotSortable就可以避免預設的排序行為。

25. 如何在點選工具欄按鈕的時候将資料送出到資料庫?

預設情況下,操作工具欄或菜單不會導緻對控件的驗證。但對于綁定控件來說,送出資料前進行驗證是必要的。而一旦窗體和其中的所有控件得到驗證,目前編輯過的資料就需要送出。最後,資料擴充卡(如SqlDataAdapter)需要将資料的修改寫入資料庫。要達到這個效果,将下面三行代碼加到相應的事件處理函數(指工具欄按鈕或菜單項的事件)内:

this.Validate();

this.customersBindingSource.EndEdit();            this.customersTableAdapter.Update(this.northwindDataSet.Customers);

26. 如何在使用者删除記錄時顯示确認對話框?

當使用者選擇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;

}

繼續閱讀