DataGridView 解析

摘要:DataGridView 解析

  • DataGridView:一種適合顯示表格資料的控制項,以 Columns屬性集合了各種類型的DataGridViewColumn對應表格中的欄位,以Rows屬性集合了DataGridViewRow對應表 格中的每一筆資料,欄位與資料行的交集為一個儲存格DataGridViewCell,用來顯示與編輯表格中的一個資料值。
  • DataGridViewColumn:代表 DataGridView中的一個欄位,因應欄位資料型態特性而衍生出不同類別,提供使用者最佳的顯示與編輯方式,可以說是構成DataGridView 的主體,以CellTemplate屬性指定的DataGridViewCell做為欄位中每一個儲存格的樣板,欄位中不同資料行會複製樣板套上資料成為 一個儲存格。如果DataGridView的AutoGenerateColumns屬性設為True,.Net會自動為DataGridView資料來 源的每一個欄位建立對應的DataGridViewColumn,若希望客製化欄位對應的DataGridViewColumn類別,就必須把 DataGridView的AutoGenerateColumns屬性設為False,自行建立DataGridViewColumn類別的執行個體, 把DataPropertyName屬性設定成對應的欄位名稱。我們可以自行開發各種DataGridViewColumn充實DataGridView 的使用者介面,所以DataGridViewColumn是讓DataGridView得以客製化的主角。
  • DataGridViewRow:代表DataGridView中的 一筆資料,會依據資料來源筆數自動動態建立,其Cells屬性是複製所有DataGridViewColumn的CellTemplate屬性套上對應的 資料值集合而成的。DataGridViewRow是一個比較被動的角色,它的形成是由資料來源筆數、欄位數及欄位指定的儲存格型態共同決定的,用來當作 存取某一筆資料的媒介,沒有太大的客製化空間。
  • DataGridViewCell:代表DataGridView中 的一個儲存格,用來顯示與編輯一個資料值,每一個DataGridViewColumn只會有一種型態的 DataGridViewCell,是由CellTemplate屬性所指定的,通常我們不會直接建立儲存格的執行個體,它是由 DataGridViewRow自行複製DataGridViewColumn的CellTemplate這個樣板產生的,唯一的例外是自行建立一個儲存 格的新執行個體做為樣板,指派給DataGridViewColumn的CellTemplate屬性取代原有的樣板。我們如果要更改單一儲存格的行為, 必須經由DataGridView的RowIndex找到DataGridViewRow,再指定ColumnIndex找到對應的 DataGridViewCell,但當DataGridView的資料來源更新時,先前對特定DataGridViewCell所作的設定也隨之消失, 如果要改變某一欄位的所有儲存格的行為,就要直接對DataGridViewColumn.CellTemplate屬性作設定,才不會在更新資料時喪失 先前所做的變動。DataGridViewCell以EditType屬性指定有實作IDataGridViewEditingControl的Type 作為儲存格資料編輯控制項的型別,由於這是一個唯讀屬性,唯有客製化的DataGridViewCell才能自訂編輯控制項的類別,改寫Paint()函 式可以自訂資料呈現的方式。
  • IDataGridViewEditingControl: 這個介面是DataGridView與資料編輯控制項溝通的接口,當使用者在編輯資料時所使用的控制項並不是DataGridView本身,而是 DataGridView的EditingControl屬性所指示的控制項,它是由正在編輯的DataGridViewCell的EditType指定 類別建立出來的執行個體,顯示在DataGridView的EditingPanel內。在預設的狀態下,DataGridView中所有 EditType相同的DataGridViewCell即使棣屬不同欄位亦會共用同一個控制項執行個體,當DataGridViewCell進入編輯模 式時會執行InitializeEditingControl()函式,把格式化的顯示值指派到IDataGridViewEditingControl 的EditingControlFormattedValue屬性(註1), 執行IDataGridViewEditingControl的ApplyCellStyleToEditingControl()函式套用與外觀設定相 關的樣式DataGridViewCellStyle,完成控制項的初始化,如果要在這個過程中新增委派給控制項的事件,則務必在結束編輯模式時移除委 派,否則委派會隨控制項不斷初始化而一直累積,當事件成立時就會一一觸發。我們可以自行開發或繼承任何現有控制項,實作 IDataGridViewEditingControl介面做為DataGridViewCell的EditType,就能客制化 DataGridView的輸入控制項。

在客製DataGridViewColumn之前還要特別注意一點,DataGridView中的資料值有二種,一個是資料來源中的值,以Value命 名,一個是格式化後顯示給使用者觀看的值,以FormattedValue命名,二者到底有什麼不同呢?舉例來說,資料來源中的Value是int型態的 1234,顯示出來的FormattedValue是string型態的1,234,以我們的思考模式來說二者代表相同的意義,沒什麼差別,但對電腦來 說,二者差了十萬八千里,光是資料型態就不同了,根本無法比較!再舉一個特例,假設資料來源中的Value是bit的0與1,我們可以把 FormattedValue變成Image的笑臉與哭臉,對使用者而言,看到的資料是簡單易懂的圖示,對程式而言需要的是容易處理又能節省空間的位元。 這二者的關係是Value經過Format程序變FormattedValue,FormattedValue經由Parse程序轉換成Value。儲存 格預設的Format程序可以直接改寫DataGridViewCell的GetFormattedValue(),個別儲存格的Format程序可以委 派給DataGridView的CellFormatting事件;儲存格預設的Parse程序可以直接改寫DataGridViewCell的 ParseFormattedValue (),個別儲存格的Parse程序可以委派給DataGridView的CellParsing事件。FormattedValue從儲存格交到資料編輯 控制項時,還會經由IDataGridViewEditingControl的EditingControlFormattedValue屬性(註1) 與GetEditingControlFormattedValue()二次加工處理,二次加工的前後差別在於,加工前是儲存格在非編輯模式時所顯示出來 的值,是直接畫在DataGridView的儲存格內,加工後是儲存格在進入編輯模式時所顯示出來的,是畫在編輯控制項內的。

註1:DataGridViewCell傳FormattedValue給控 制項,理論上應該要設定IDataGridViewEditingControl的EditingControlFormattedValue屬性值,但 實測發現以DataGridViewTextBoxCell為例,它是直接設定TextBox的Text屬性,我十分不認同Microsoft研發小組這 種跳過IDataGridViewEditingControl直接把FormattedValue給控制項的做法,這等於是認定控制項一定得是某種類 別,讓IDataGridViewEditingControl喪失做為接口的功能,其它實作IDataGridViewEditingControl的 控制項就無法與這個DataGridViewCell正常運作。

 

 

 

DataGridView.Event

    DataGridView_CellContentClick
        配合DataGridViewButtonColumn,即 ButtonCell 來使用。
    DataGridView_CellValidated
        在Cell上輸入資料的驗証後續處理。
        此event 在CellValueChanged之前觸發。
        應用上注意:此段的資料操作指令層級不要透過UI層,如:「DataGridViewCell.Value」等,否則可能會造recursive cycle 的無止盡迴圈。因為用 「DataGridViewCell.Value」操作資料會觸發「CellValidated」、「CellValueChanged」等訊息。
        應用上注意二:儘可能讓DataGridView 與DataSet(or DataTable)進行binding,可省下很多資料搬遷的動作。透過binding 技術,用 DataSet 來操作資料,其處理結果會直接映射到DataGridView。
    DataGridView_CellValueChanged
        在Cell上的新值Commit後觸發,處理延伸計算,像是用代碼取名稱等。
        或用於同一筆DataGridViewRow但不同Cell間的計算,如:Cell3 = Cell2 * Cell1,等等的相依性計算。
        應用上注意:一樣的,不要用UI層的指令,如:DataGridViewCell.Value 等,以免 recursive 。
    DataGridView_CellBginEdit
    DataGridView_EditingControlShowing
    DataGridView_CellEndEdit
        切換到編輯模式時觸發。順序是CellBginEdit  -> EditingControlShowing  -> CellEndEdit,其中可用method EndEdit() 來提前結束編輯模式。
    DataGridView_DataError
        攔截 Cell Exception 的地方

DataGridView.DataMember:

    DataGridView.Columns
    DataGridViewColumn.Name
        用來取欄位識別名稱,如下面這行指令:
        String ccName = dgvItems.Columns[e.ColumnIndex].Name; // current cell id-name;
    DataGridView.Rows
    DataGridViewRow.DataBoundItem
    DataRowView.Row
        其中,「DataGridViewRow.DataBoundItem」與「DataRowView.Row」配合用來取其資料來源實體,如下面兩行指令:
        DataGridViewRow cvr = dgvItems.Rows[e.RowIndex]; // current gridview-row.
        DataRow dr = ((DataRowView)cvr.DataBoundItem).Row; // current data-row.
        MetaDataSet1.MetaAstItemRow cdr = (MetaDataSet1.MetaAstItemRow)((DataRowView)cvr.DataBoundItem).Row; // current data-row. 這行才是本人實務上使用的方法。

 

DataGridView.Methods :

DataGridView.BeginEdit()
DataGridView.EndEdit()
DataGridView.CancelEdit()

    編輯模式控制

DataGridView.InvalidateCell()
DataGridView.InvalidateRow()
DataGridView.InvalidateColumn()

    強制重繪畫面。

DataSet.BeginInit Method
DataSet.EndInit Method
DataTable.BeginInit Method
DataTable.EndInit Method
DataTable.BeginLoadData Method
DataTable.EndLoadData Method
Control.SuspendLayout 方法
Control.ResumeLayout 方法