1. 程式人生 > >GridView獲取隱藏列值的詳細總結

GridView獲取隱藏列值的詳細總結

這個問題是比較常見的,網上也有不少類似文章,最近做專案也遇到這個問題,這裡在自己分析基礎上,結合實際問題,總結這一問題的幾種解決方案。

問題提出:在使用GridView控制元件時候,往往需要對某一列進行隱藏,而在後臺程式碼中,有時卻又需要這個隱藏列的值來進行一些別的操作,比如我就遇到一個實際問題:控制元件GridView的ID為GV,其中某一列X(X為索引號)的所有單元格的背景顏色,需要根據另一列Y(Y為索引號)的數值來確定,而Y這一列是我不想讓使用者看到的,所以需要隱藏Y列,可是問題出來了,用如下方式設定了列的不可見:

?
1 GV.Columns[Y].Visible=false
;

卻發現之後在取這一列中單元格的值時,始終是為空,也就是說這種隱藏方式後,無法訪問單元格的數值了。另外,用這個方法在特定問題時還有另外一個弊端,這個在解決方法2中會提到。

問題分析:GridView是Asp.net 2.0中增加了一個新的資料繫結控制元件,其目的用來取代Asp.net1.x中的DataGrid控制元件,以前用DataGrid時候,上述問題是不存在的,即使設定了列的隱藏,也可以進行訪問。通過網上找一些類似的問題,可以知道,如果把某列的Visible屬性設false,則不會進行資料繫結,也就是說無法直接從GridView中取到這個列內的數值。因此,這就需要既要用別的方式來隱藏列,又要取到隱藏列的值。

解決方法:

1.隱藏列前獲取資料

看這樣一個例子(以下均以此為例):使用者選擇一些查詢條件後,點選“查詢”按鈕。後臺需要根據每行中第六列的值是否為1,來設定第三個單元格的背景色為紅色。

這種方法中,後臺是在按鈕的Click事件中,去資料庫取記錄,然後得到DataTable,最後將它繫結到GridView中。如果我們需要在GridView的RowDataBound事件中取隱藏列的值,則用Visible屬性來設定某一列為隱藏,是沒問題的。如下程式碼:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected
void Btn_Query_Click(objectsender, EventArgs e) { DataTable dt = new DataTable(); dt=ConstructActiveDataTable();//一個取記錄的方法 GV.DataSource = dt; GV.DataBind(); GV.Columns[5].Visible =false;//設定第6列為隱藏 } protectedvoid GV_UpdateData_RowDataBound(objectsender, GridViewRowEventArgs e) { if(e.Row.RowType == DataControlRowType.DataRow) { if(e.Row.Cells[5].Text.ToString() == "1")//當行中的第六個單元格的值為1時(第六列為隱藏哦) { e.Row.Cells[2].BackColor = System.Drawing.Color.Red;//設定行中第三個單元格背景色為紅色 } } }

為什麼這樣就可以了呢?其實是利用了在隱藏列之前就把數值取到了,然後最後再隱藏列。因為在Click事件中,當GV.DataBind()後,不是執行了GV.Columns[5].Visible = false,而是立刻觸發了RowDataBound事件,等執行完了此事件,才繼續回去執行的隱藏列的程式碼。因此,這類特定問題中,只要利用事件或函式呼叫的順序關係,即可避免無法取值的問題。

當然,這一解決方案並非通用,它對程式碼執行順序有要求。

2.分別隱藏列中每個單元格

有些時候,我們不想用上面那種手動方式(DataBind())來繫結GridView了,而是使用一些已有的資料來源控制元件,比如:objectdatasource控制元件。將GridView的DataSourceID指定為objectdatasource控制元件的ID,則objectdatasource控制元件指定其SelectMethod屬性為一個返回型別是集合型別的函式(比如返回DataTable),就會在後臺自動去呼叫這個函式並繫結(具體方法就不說了)。

那麼依然是上面那個應用,根據隱藏列值來設定另一個單元格的背景顏色,上面那個順序就不可能實現了,因為類似於DataBind的繫結是隱式執行的,雖然他可能也是繫結後立刻觸發RowDataBound事件,然後回去執行剩餘程式碼,但是我們不能在剩餘程式碼中再如上面的插入設定列隱藏的程式碼。因此,依靠控制程式碼順序來實現不太可能了,這是第一個問題。另外,還有一個問題(問題提出中所指),就是這個控制元件比較怪,如果你在用objectdatasource繫結後,設定了一次列的Visible,那麼objectdatasource就會重新去繫結一次資料,那麼如果隱藏10個列,豈不是要去重新從資料庫等資料來源重複讀十遍資料,這個效能上是不可接受的。

鑑於這兩個原因,必須有別的方法來隱藏列。

既然列是由單元格形成的,那麼一一隱藏單元格肯定也能達到隱藏的效果,但是隱藏後能否獲取到其值呢,經過驗證,確實可以。不過要注意,Footer,Header和DataRow中的單元格都需要隱藏哦,否則表格就錯位了。隱藏的程式碼放哪裡都可以,建議放在RowDataBound事件中,這樣每生成一行就去隱藏相應列即可。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protectedvoid GV_UpdateData_RowDataBound(objectsender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.Header || //如果設定gridview不顯示Header,就不寫這個(否則報錯) e.Row.RowType == DataControlRowType.DataRow ||  e.Row.RowType == DataControlRowType.Footer)   //如果設定gridview不顯示Footer,就不寫這個(否則報錯) { e.Row.Cells[5].Visible=false;//設定每一行中第六個單元格為隱藏,達到隱藏第六列的目的 } if(e.Row.RowType == DataControlRowType.DataRow) { if(e.Row.Cells[5].Text.ToString() == "1")//即使隱藏了,依然可以訪問到數值哦 { e.Row.Cells[2].BackColor = System.Drawing.Color.Red;//設定行中第三個單元格背景色為紅色 } } }
?
1

依然有人認為這程式碼不夠好,有些人不喜歡用事件,另外也擔心效能問題,畢竟每一行都要觸發這個事件。

3.利用新的屬性DataKeys和DataKeyNames

事實上,微軟所作的考慮更加周全。針對GridView無法提供行主鍵的問題,它提供了兩個全新的屬性:DataKeys和DataKeyNames!其SDK中的描述如下:
DataKeyNames:獲取或設定一個數組,該陣列包含了顯示在 GridView 控制元件中的項的主鍵欄位的名稱。
DataKeys:獲取一個 DataKey 物件集合,這些物件表示 GridView 控制元件中的每一行的資料鍵值。

也就是說,利用DataKeyNames,可以設定一個多個列,用於作為行的主鍵欄位(這裡用主鍵其實不太合適,因為值時允許重複的),之後利用DataKeys舊可以訪問這些列的值了。因此,利用這兩個新屬性,我們就可以繼續使用利用列的Visible屬性設定來隱藏列的同時,又可以訪問隱藏列的值了。方法如下:

?
1 2 3 4 5 6 7 8 GV.Columns[5].Visible = false;//設定第6列為隱藏 //只需要在設定列為隱藏的地方多加一段程式碼: GV.DataKeyNames = new string[] {"stateid_O2" }; //假設第六列的列名為stateid_O2 protected void GV_UpdateData_RowDataBound(object sender, GridViewRowEventArgs e) { if (GridView_UpdateData.DataKeys[e.Row.DataItemIndex]["stateid_O2"].ToString() =="1")
?
1 2 3 4 5 //利用這個DataKeys屬性來訪問隱藏列的值 { e.Row.Cells[2].BackColor = System.Drawing.Color.Red;//設定行中第三個單元格背景色為紅色 } }

4.利用客戶端程式碼來隱藏列

實際上,我們上面都是在伺服器端利用各種方法來隱藏列了,那麼這種方法就是伺服器端不對列的可見性進行設定,那麼顯然就不存在無法取值的問題了,那麼又要讓使用者不看到某些列,這就需要客戶端的程式碼css來實現隱藏效果了。可以從上面方法推匯出,既可以用css直接隱藏列,也能通過隱藏列的單元格來實現。首先需要一個css:

?
1 2 3 <style type="text/css"> .hidden{ display:none;} </style>

如果GridView的列是事先確定,也就是通過設計器來新增的,那麼只需要在設計時,將相應列的FootStyle,HeaderStyle,ItemStyle的CssClass屬性為“hidden” 即可。如下圖所示:

截圖00

當然,如果列是動態的,或者隱藏哪一列只有在繫結後才能確定,那麼就必須在後臺設定css。設定有兩種方法:

一種是設定的css:

?
1 2 3 4 5 6 protected void GridView_UpdateData_RowDataBound(object sender, GridViewRowEventArgs e) { GV.Columns[5].HeaderStyle.CssClass ="hidden"; GV.Columns[5].ItemStyle.CssClass ="hidden"; GV.Columns[5].FooterStyle.CssClass ="hidden";                         }

另一種是設定單元格的css:

?
1 2 3 4 5 6 7 8 9 10 11 12 protected void GV_UpdateData_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.Header || //如果設定gridview不顯示Header,就不寫這個(否則報錯) e.Row.RowType == DataControlRowType.DataRow ||  e.Row.RowType == DataControlRowType.Footer)    //如果設定gridview不顯示Footer,就不寫這個(否則報錯) { e.Row.Cells[5].CssClass ="hidden"; } }

總結:

第一種方法不太通用,要求在隱藏列前就去訪問值,這個是一個約束條件。第二種通過伺服器端隱藏列中每個單元格來實現效果,效率一般;第三種應該是標準方式,利用新的屬性來達到目的,需要熟悉他的用法;最後一種是在客戶端進行隱藏,但是資料還是傳到客戶端了,如果不介意這樣一點多出的資料量,這個應該最容易理解和使用。