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

 

爲什麼這樣就可以了呢?其實是利用了在隱藏列之前就把數值取到了,然後最後再隱藏列。因爲在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. protected void GV_UpdateData_RowDataBound(object sender, GridViewRowEventArgs e)    
  2.  {    
  3.   if(e.Row.RowType == DataControlRowType.Header || //如果設置gridview不顯示Header,就不寫這個(否則報錯)
  4. e.Row.RowType == DataControlRowType.DataRow || 
  5. e.Row.RowType == DataControlRowType.Footer)    //如果設置gridview不顯示Footer,就不寫這個(否則報錯)
  6.     {    
  7.     e.Row.Cells[5].Visible=false;//設置每一行中第六個單元格爲隱藏,達到隱藏第六列的目的    
  8.     }    
  9.     if (e.Row.RowType == DataControlRowType.DataRow)    
  10.      {    
  11.        if (e.Row.Cells[5].Text.ToString() == "1")//即使隱藏了,依然可以訪問到數值哦    
  12.          {    
  13.            e.Row.Cells[2].BackColor = System.Drawing.Color.Red;//設置行中第三個單元格背景色爲紅色    
  14.          }    
  15.      }    
  16.  }   

 

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

3.利用新的屬性DataKeys和DataKeyNames

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

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

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

 

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

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

  1. <style type="text/css">    
  2.     .hidden { display:none;}    
  3. </style>   如果GridView的列是事先確定,也就是通過設計器來添加的,那麼只需要在設計時,將相應列的FootStyle,HeaderStyle,ItemStyle的CssClass屬性爲“hidden” 即可。如下圖所示:

 

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

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

一種是設置的css:

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

 

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

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

總結:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章