GridView是ASP.NET界面開發(fā)中的一個重要的控件,對GridView使用的熟練程度直接影響軟件開發(fā)的進度及功能的實現(xiàn)。(車延祿)
GridView的主要新特性:
1.與DataSource控件結合實現(xiàn)了顯示與數(shù)據(jù)操作的分離,大大減化了代碼的編寫量;
2.實現(xiàn)"雙向綁定",無需手動檢索數(shù)據(jù)。
2.在列的類型上新增了CheckBoxField和ImageField兩個類型列;
3.對排序和分頁可以實現(xiàn)異步操作;
4.對其視圖狀態(tài)進行優(yōu)化,使其運行效率更高;
GridView與DataSource控件
要談GridView就必需要談DataSource,這兩個對象可稱得上是“最佳拍檔”。DataSource控件負責與數(shù)據(jù)源的交互,而GridView負責數(shù)據(jù)的顯示。它們之間通過“雙向綁定”聯(lián)系起來,即DataSource控件將檢索出來的數(shù)據(jù)綁定到GridView中顯示,而GridView中修改和刪除的數(shù)據(jù)直接綁定到DataSource數(shù)據(jù)源去。這兩個過程由這兩個控件相互配合實現(xiàn)的,無需我們編寫代碼。如果我們只用GridView顯示數(shù)據(jù),而不用DataSource控件的話,那你只好編寫代碼實現(xiàn)DataSource要作的工作了。做為用過VS2003的用戶對這個工作并不陌生,但這種代碼實現(xiàn)不但工作量大,而且使用復雜,容量產(chǎn)生大量可讀性差的代碼,當然也是初學者的最大障礙。好在VS2005為我們提供了DataSource控件,使我們不再如此痛苦地Coding了(當然,如果有的情況下DataSource控件還無法完全替代Coding)。
所以在使用GridView控件的時候我們最好配合DataSource控件使用,不要再去折磨自己了。 下面的案例不做特殊說明均以GridView+DataSource控件實現(xiàn)。
一、GridView外觀設置:
1、總體外觀設置
ShowFooter:(bool)是否顯示頁腳
ShowHeader:(bool)是否顯示頁眉
GridLines:(enum)None-不顯示格線;Horizontal-顯示水平格線;Virtical-顯示豎直格線;Both-顯示水平和豎直格線
EmptyDataText:(string)如果數(shù)據(jù)源中內容為NULL時在GridView中顯示的值
AlternatingRowStyle:交替項的樣式
EditRowStyle:編輯項的樣式
EmptyDataRowStyle:空數(shù)據(jù)項的樣式
FooterStyle:頁腳樣式
HeaderStyle:頁眉樣式
PagerStyle:分頁樣式
RowStyle:行樣式
SelectedRowStyle:選中項樣式
注:1、使用GridView的時候我們一般可以使用“自動套用樣式”選中一個樣式,然后在此樣式的基礎上修改上面的屬性,從而制作出滿意外觀效果。
2、上面的樣式可以對GridView進行總體的外觀設置,如果對某一列進行設置的話那可要在GridView右上角“智能菜單中”點擊“編輯列”進行設置。
如:
直接套用樣式后的外觀

修改RowStyle-BackColor、RowStyle-Font、RowStyle-HorizontalAlign 等屬性后的效果

2、對綁定列進行外觀設置
對上面的圖我們可以看出外觀方面有幾個問題:
a.頁眉是英文的
b.所有的數(shù)據(jù)都是居中對齊
c.time列的數(shù)據(jù)中顯示了時分秒的數(shù)據(jù)
d.price列中應加上"RMB"的符號
e.最好對價格列的數(shù)據(jù)以紅色字體顯示
上面的這些問題我們可以通地單獨對列進行格式設置來實現(xiàn)
點擊GridView右上角“智能菜單中”點擊“編輯列”,打開"字段"窗口:

這個圖總體可以分作三大部分:可用字段,選中的字段,BoundField屬性
(1)“可用字段”:顯示了可供我們使用的列的類型
BoundField:綁定列,將數(shù)據(jù)庫中的數(shù)據(jù)以字符形式綁定顯示
CheckBoxField:復選框列,一般用來綁定數(shù)據(jù)庫中的Bit型數(shù),以復選框的形式顯示在GridView中
HyperLinkField:超鏈接列,可以用數(shù)據(jù)源中的數(shù)據(jù)作超鏈接文本也可以把所有超鏈接文本設為統(tǒng)一的文本
ImageField:圖片列,綁定數(shù)據(jù)源中的圖片路徑,并把圖片顯示出來
CommandField:命令列,常用的“選擇”,“刪除”,“編輯、更新、取消”
ButtonField:按鈕列,其它做用的按鈕
TemplateField:模板列,可以更靈活地自定義顯示格式
(2)“選定的字段”:從“可用字段”中添加進來的,用來在GridView中顯示的列。其下方有個復選框“自動生成字段”,如果選中了就會根據(jù)DataSource控件中檢索出來的數(shù)據(jù)自動生成列,如果你要自己設置列的格式,請將此復選框清空。(車延祿)
(3)“BoundField屬性”:設置“每個可用字段”的屬性
我們可以根據(jù)自己的需要從“可用字段”中選擇列添加到“選中的字段中”,然后設置BoundField屬性。
在此我們先主要看BoundField列,其它類型的列后面再講解。
BoundField中的重要屬性:
ControlStyle:當前列中控件的樣式
HeaderStyle:當前列中頁眉的樣式
FooterStyle:當前列中頁腳的樣式
ItemStyle:當前列中數(shù)據(jù)行的樣式
ReadOnly:當前列是否是只讀列,編輯的時候不顯示文本框
SortExpression:排序表達式,這里只填數(shù)據(jù)源的列名
Visible:當前列是否可見
HeaderText:頁眉文本
FooterText:頁腳文本
DataField:當前列的數(shù)據(jù)行要顯示哪個字段的數(shù)據(jù),填寫字段名
DataFormatString:對顯示的數(shù)據(jù)進行格式化顯示
上面的屬性太多,大家可以一時記下來,其實也沒必要去記,只要見文知意就可以了。下面我們就用上面的內容來解決外觀方法的問題
第一步:清空“自動生成字段”復選框
第二步:從“可用字段”中選擇“BoundField”添加到“選定的字段”中
第三步:點擊“選定的字段”中的每個字段,在“BoundField屬性”中設置
HeaderText--頁眉文本。如:“汽車名稱”
DataField--要在此列顯示數(shù)據(jù)的列名
第四步:設置"name"列的ItemStyle中的HorizontalAlign屬性為left,這樣只把name列的數(shù)據(jù)左對齊
第五步:設置"price"列的ItemStyle中的HorizontalAlign屬性為right,這樣只把price列的數(shù)據(jù)右對齊
第六步:在time列的DataFormatString屬性中設置為:"{0:d}"
第七步:在price列的DataFormatString屬性中設置為:"<font color=red>RMB</font>{0}"

好了,大家可以看到上面的問題我們都已解決了,效果還可以吧。
3、對數(shù)據(jù)行進行外觀設計
對于列的設計我們可以通過可視化的界面進行設計,但是對于數(shù)據(jù)行的外觀設置就沒有那么簡單了。由于我們不知道將來有多少行數(shù)據(jù)顯示,也不知道哪一條數(shù)據(jù)顯示在哪一行中,所以很難通過可視化的方式進行設置。但這并不代表我們沒有辦法根據(jù)綁定的數(shù)據(jù)不同設置不同行的外觀。
要解決這個問題我們先來研究一下GridView的綁定數(shù)據(jù)的過程:
當我們?yōu)镚ridView設置了已配好數(shù)據(jù)源后,在運行的時候,會把數(shù)據(jù)源中的數(shù)據(jù)綁定顯示出來。但由于GridView隱藏了自身在數(shù)據(jù)綁定過程中的構建過程,所以使好多學JavaEE的同學感覺不如在<Table>標記中嵌入for循環(huán)清晰,更使有的同學感到“GridView自動生成的行讓人有點不太放心”。其實,這是個思維導向的問題,只要我們理解了在數(shù)據(jù)綁定時GridView界面的構建過程,就不難發(fā)現(xiàn)GridView數(shù)據(jù)綁定的思路并不復雜。關鍵的是大家不要羈絆于JavaEE生成表格的思路中,要以一種開放與求知的心態(tài)來研究GridView。
實際上在GridView在數(shù)據(jù)綁定的過程中是逐行實現(xiàn)的。是從GridView最上面的一行(頁眉或上分頁行)到最下面的一行(頁腳或下分頁行)逐行建造的。在建造每一行的過程中,又分為兩步:創(chuàng)建行和綁定行兩個步驟。下面分開說:
創(chuàng)建行:就是根據(jù)數(shù)據(jù)源的結構創(chuàng)建出n個單元格,并根據(jù)GridView的樣式和BoundFField屬性的樣式設置好每個單元格的樣式(背景色,前景色,字體等)。如果該行中有控件或靜態(tài)文本(設計時已寫死的文本,如頁眉文本)那在創(chuàng)建的時候也會直接創(chuàng)建控件或靜態(tài)文本。就像開茶館一樣,把椅子、桌子、茶杯、開水都備好了,就等客人來了(客人還沒來呢,因為這只是創(chuàng)建行,還沒有綁定行呢)。
綁定行:“創(chuàng)建行”執(zhí)行完后,再進行“綁定行”。綁定行實際上就是把數(shù)據(jù)源中當前行的數(shù)據(jù)逐一填寫到已創(chuàng)建好的行的相應單元格里去。綁定行執(zhí)行完畢時才真正把一行數(shù)據(jù)建造完畢。這里就像把客人按排到相應的已準備好的坐位上喝茶。
在GridView綁定DataSource控件的時候實際上就是循環(huán)執(zhí)行“創(chuàng)建行”和“綁定行”的過程。如果我們能深入到每一行的“建造”過程中去,我們就可以根據(jù)綁定出來的數(shù)據(jù)控制當前行的外觀樣式了。
非常幸運,GridView 為我們提供了兩個事件:RowCreated和RowDataBound事件

RowCreated事件:是每一行“創(chuàng)建行”完成時被觸發(fā)的事件。
RowDataBound事件:是每一行“綁定行”完成時被觸發(fā)的事件。
因此在綁定GridView顯示數(shù)據(jù)過程也就是循環(huán)觸發(fā)RowCreated事件和RowDataBound事件的過程。
下面的代碼驗證了我上面的闡述:(車延祿)
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
Response.Write(e.Row.RowType.ToString()+" Created=>");
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Response.Write(e.Row.RowType.ToString()+" DataBound=>");
}
執(zhí)行結果:

好了通過上面的講述,大家應當明白GridView的綁定過程了,也正有了上面的RowCreated和RowDataBound這兩個能被自動觸發(fā)的事件,我們就可以像孫猴子鉆入鐵扇公主的肚子里那樣鉆入到GridView的創(chuàng)建過程中去,想怎么拆騰就怎么拆騰,完全由你了。
那下面我們就拆騰一下吧,對數(shù)據(jù)行實現(xiàn)下面的控制:
1.把“上市時間”列改為"yyyy年MM月dd日"的中文格式顯示
2.把價格高于50萬元的高檔汽車用黃色前景和紅色字體顯示
3.計算當前頁面中所有汽車的平均價格,并顯示在頁腳中
解決思路:
在GridView控件的RowDataBound事件中,取得每一行中相應單元格中的數(shù)據(jù),把數(shù)據(jù)處理,重新寫回單元格中。
代碼如下:
//成員變量,用來累計當前頁面中所有汽車的價格總和
private double _PriceSum;
protected void Page_Load(object sender, EventArgs e)
{
//顯示頁腳,以便在其中顯示平均價格
GridView1.ShowFooter = true;
}
//修改日期的顯示格式
private void ChangeDate(GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
//取出“上市時間”單元格中的日期文本
string dt = e.Row.Cells[3].Text;
if (dt != null && dt.Trim() != "")
{
//將日期轉換為長日期字符串格式
e.Row.Cells[3].Text = Convert.ToDateTime(dt).ToLongDateString();
}
}
}
}
//把價格大于50萬的汽車用黃色背景紅色字體顯示
private void HighLightCar(GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
string strprice = e.Row.Cells[4].Text;//取出來的單元格的文本帶有RMB字符串,如:<font color=red>RMB</font>50.47
//截取出其中的價格
strprice = strprice.Substring(strprice.LastIndexOf(">")+1);
//將價格轉換為double型數(shù)據(jù)
double price = double.Parse(strprice);
if (price > 50)
{
e.Row.BackColor = System.Drawing.Color.Yellow;//使用預設顏色來設置行的背景色
e.Row.ForeColor = System.Drawing.Color.FromName("#ff0000");//使用十六進制的顏色,設置前景色
}
}
}
}
//計算當前頁中所有汽車的平均價格,并在頁腳顯示
private void GetAvgPrice(GridViewRowEventArgs e)
{
//累加當前頁中的汽車的價格總和(_PriceSum)
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
string strprice = e.Row.Cells[4].Text;//帶有RMB字符串,如:RMB50.47
strprice = strprice.Substring(strprice.LastIndexOf(">") + 1);
double price = double.Parse(strprice);
_PriceSum += price;
}
}
//根據(jù)_PriceSum計算平均價格,并在頁腳顯示
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[4].Text = "<font color=red>RMB</font>"+(_PriceSum / GridView1.PageSize).ToString();
e.Row.Cells[4].HorizontalAlign = HorizontalAlign.Right;
}
}
//RowDataBound事件處理程序,調用上面的三個方法進行設置
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
ChangeDate(e);
HighLightCar(e);
GetAvgPrice(e);
}
執(zhí)行結果:

在上面的函數(shù)中,有幾個需要重點說明的問題:
1.GridViewRowEventArgs e形參:這是在建造行對象時產(chǎn)生的事件數(shù)據(jù),它里面包含正在建造的當前行對象的信息,通過它我們可以取得正在建造的行對象和行對象中的單元格對象,并可以取得或設置這些對象相應的屬性。
2.e.Row.RowType屬性:(DataControlRowType枚舉類型)它返回正在建造的行對象的類型(如:頁眉、頁腳、數(shù)據(jù)行、分頁行等)
3.e.Row.RowState屬性:(DataControlRowState枚舉類型)它返回正在建造的行對象的狀態(tài)(如:普通狀態(tài)、交替狀態(tài)、編輯狀態(tài)、選中狀態(tài)等)
下面這段代碼,大家一定不能漏掉
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
}
}
它代表我們的操作只對數(shù)據(jù)行起作用,不對頁眉和頁腳起作用(因為頁眉頁腳的文本中并不包含我們需要的數(shù)據(jù))。并且僅當數(shù)據(jù)行處理普通狀態(tài)和交替狀態(tài)時起作用,在編輯和選中狀態(tài)不是不起作用的(編輯狀態(tài)下,數(shù)據(jù)不是顯示在單元格的Text中,而是顯示在單元格的控件中的)。(車延祿)
二、超鏈接列的使用
超鏈接列也是開發(fā)過程中使用比較多的列的類型,它是在GridView的單元格中顯示超鏈接信息,在點擊超鏈接時跳轉到相應的頁面上去。

如上圖所示,由于我們Car表中的列很多,如果在一個頁面中全顯示出來會使GridView中單元格的數(shù)據(jù)變形,很影響我們的外觀。我們可以只把幾項主要信息顯示出來,然后在每一行的后面加一個超鏈接列,當點擊超鏈接列時轉到一個詳細頁面,把每一型號汽車的具體信息詳細顯示出來。
效果如下圖
汽車列表頁面

汽車詳細信息頁面

下面我們看看如何實現(xiàn)這種效果
第一步:向頁面中加入ObjectDataSource,GridView并配置好它們。
第二步:點擊GridView的智能菜單進入GridView字段設置頁面,如下圖所示
設置DataNavigateUrlField為主鍵列Code
設置DataNavigateUrlFormatterString為Default7.aspx?id={0}
設置HeaderText為"查看"
設置Text為"詳細"
第三步:點擊確定按鈕完成添加

這里的屬性較多,在這里我們一起來看一下
HeaderText:該超鏈接列的頁眉文本
FooterText:該超鏈接列的頁腳文本
Text:超鏈接列中的鏈接文字,這個屬性用來把該列所有單元格的超鏈接的文字設成相同的。
DataTextField:指定數(shù)據(jù)源的一個字段名,把該字段的內容作為超鏈接列的超鏈接文本。如果同時設置了Text屬性和DataTextField屬性,則忽略Text屬性的設置。
DataTextFormatterString:為綁定顯示的DataTextFied數(shù)據(jù)設置顯示格式
DataNavigateUrlField:指定數(shù)據(jù)源的一個字段名,該字段的內容作為超鏈接列導向的網(wǎng)址,或者把該字段的值作為超鏈接傳遞的參數(shù)。
DataNavigateUrlFormatterString:為 DataNavigateUrlField列設置超鏈接的導航格式。如Default7.aspx?id={0}則該列的超鏈接導航到 Default7.aspx頁面,并且把DataNavigateUrlField中指定的字段值賦給id,作為查詢字符串傳遞至 Default7.aspx頁面
如果超鏈接列需要向目標頁面傳遞多個字段的值作為參數(shù)的話,那么請在DataNavigateUrlField中指定多個字段名并用逗號隔開,然后再在DataNavigateUrlFormatterString屬性中用"&"鏈接多個參數(shù)(如:default7.aspx?id={0}&name={1})
三、命令列的使用
命令列主要提供了GridView中常用的一些修改、更新、刪除的操作,在GridView與DataSource控件結合使用的情況下,我們并不需要為些編寫太多的代碼就可以實現(xiàn)簡單的維護操作,如果在復雜的情況下(如一對多鏈接查詢時),我們仍需要編寫代碼來實現(xiàn)更新與刪除。(車延祿)

使用命令列有兩種方式:
1.在“可選列”中添加相應的CommandField列的子項
2.在“可選列”中添加CommandField列,然后設置CommandField列的屬性ShowEditButton、ShowDeleteButton等
一旦添加了命令按鈕,我們就可以對GridView實現(xiàn)簡單的修改和更新的操作了。但是如果要想實現(xiàn)刪除操作的話還不行,還需要為GridView設置一個DataKeyNames屬性。如果不設置此屬性的話編譯是沒問題的,但運行時會產(chǎn)生“未提供參數(shù)”的異常,這一點切記。

DataKeyNames屬性用來設置GridView對應的數(shù)據(jù)源的主鍵列,只有設置這個屬性,在刪除的時候才會把要刪除的主鍵值傳遞給DataSource控件執(zhí)行刪除功能。
現(xiàn)在編輯界面如圖:

我們一起來看一下運行結果所存在的問題:
1.主鍵列Code不應當被編輯
2.GridView自動產(chǎn)生的文本框太寬,把我們的GridView都給擠變形了。
3.民族列在瀏覽時一直都顯示民族代號,應當顯示民族名稱
4.民族列在修改的時候最好使用下拉列表讓用戶選擇相應的民族。
5.文本輸入框沒有任何驗證,對輸錯的信息在提交的時候會產(chǎn)生異常
6.刪除時沒有確認提示
7.刪除時產(chǎn)生外鍵引用的異常
這里的問題實在是太多了,有的問題很簡單就可以解決,但有的問題我們借助后面的模板列會更簡單一些。
1、防止某列被編輯,只需要在“編輯列”對應框中將該列的ReadOnly屬性設為true就可以了。
2、代碼控制編輯狀態(tài)下文本框的寬度(這種方式有點復雜,可以用模板列實現(xiàn))
我們上面已經(jīng)分析過GridView每一行的建造過程了,它包含“創(chuàng)建行”和“綁定行”兩步操作,“創(chuàng)建行”的過程中會把一些靜態(tài)的東西創(chuàng)建出來,當然也包含文本框的創(chuàng)建。因此我們只需要在RowCreated事件中把編輯列中的文本框的長度改變一下就可以了。
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//這里可能是VS2005的一個Bug,所以我只好把整型強制轉為DataControlRowState枚舉類型再與e.Row.RowState屬性進行比較
//4-Normal行的編輯狀態(tài),5-Alternating行處于編輯狀態(tài)
if (e.Row.RowState == (DataControlRowState)4||e.Row.RowState==(DataControlRowState)5)
{
//Width屬性是Unit類型,不能直接賦整型值
//Unit.Pixel():按像素設置絕對寬度;Unit.Percent():按百分比設置寬度
((TextBox)e.Row.Cells[1].Controls[0]).Width = Unit.Pixel(60);
((TextBox)e.Row.Cells[3].Controls[0]).Width = Unit.Pixel(60);
((TextBox)e.Row.Cells[4].Controls[0]).Width = Unit.Pixel(100);
}
}
}

3.瀏覽狀態(tài)時顯示民族名稱,只需要將實體中添加一個只讀屬性NationName,然后用它替換Nation字段,綁定到GridView就可以了。
4.對主表中的數(shù)據(jù)刪除時級聯(lián)刪除相關子表數(shù)據(jù)
這種問題用很多種實現(xiàn)方式:
a.使用數(shù)據(jù)庫中外鍵的級聯(lián)刪除功能
b.使用存儲過程或觸發(fā)器。
c.在程序代碼中刪除
前兩種方式實現(xiàn)方式主要是數(shù)據(jù)庫方面的知識,這里不多說了,下面我們主要看看如何使用程序代碼刪除數(shù)據(jù)。
當我們點擊刪除按鈕的時候,GridView會自動把要刪除的行對象傳遞給DataSource控件,然后DataSource調用相關的業(yè)務類的方法執(zhí)行刪除,再然后就發(fā)生“外鍵引用異常”......
整個這個過程是系統(tǒng)自動完成的,那我們要想自己寫代碼進行級聯(lián)刪除,并且禁止系統(tǒng)自動調用默認的刪除功能,那如何實現(xiàn)呢?
下面顯示了GridView中的一部分事件

大家會注意到其中的事件大部分都有兩類:***ed和***ing兩類。如:Deleted和Deleting事件
***ed事件:系統(tǒng)執(zhí)先完操作后觸發(fā),如Deleted事件是系統(tǒng)調用默認刪除功能,刪除成功后自動觸發(fā)
***ing事件:系統(tǒng)執(zhí)行操作之前觸發(fā),如Deleting事件是系統(tǒng)調用默認刪除功能之前觸發(fā)。
現(xiàn)在大家應當清楚在點擊刪除按鈕后如何添加自己的刪除處理程序了,答案當然是應當在Deleting中編寫代碼進行級聯(lián)刪除。
主要代碼如下:
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
//取得要刪除行的主鍵的值
string str = GridView1.DataKeys[e.RowIndex].Value.ToString();
//使用事務
using (TransactionScope ts = new TransactionScope())
{
//刪除該主鍵值在刪除簡歷表中對應的數(shù)據(jù)
new WorkDA().deleteInfo(str);
//刪除該主鍵值在刪除家庭關系表中對應的數(shù)據(jù)
new FamilyDA().deleteInfo(str);
//刪除該主鍵值在基本信息表中對應的數(shù)據(jù)
new InfoDA().delete(str);
//提交事務
ts.Complete();
}
//取銷事件進一步響影,即該刪除操作不再往上提交至DataSource控件。
e.Cancel = true;
}
問題還沒全部解決,剩下的問題我們留給模板列來解決。(雖然不用模板列也可以解決上面所有的問題,但是那可需要大量的Coding,所以建議大家使用模板列)
四、模板列
關于模板列我們可以用四個字來描述--“無所不能”。很多棘手的問題,在遇到模板列的時候會迎刃而解,因為模板列的定制功能很強大,允許我們建立不同狀態(tài)下的模板,所以我們用代碼控制起它來也就更加靈活自如了。(車延祿)
創(chuàng)建模板列一般有兩種方式:
在“編輯列”對話框中向“選中列”中添加TemplateField字段
在“編輯列”對話框中點擊“選中列”中相應的列,再點擊“確定”按鈕上方的“將此字段轉換為TemplateField”文字,這就把現(xiàn)有的列轉換為模板列了。這種轉換方式大家要小心使用,因為一旦轉換為模板列,就沒辦法再轉換回去了。
當一個綁定列被轉換成模板列后會發(fā)生如下變化:
變化前的代碼:

變化后的代碼:

變化后的設計界面

通過上面的圖我們可以看到,當一個綁定列轉換為模板列后,該列的數(shù)據(jù)顯示時,會把數(shù)據(jù)源的數(shù)據(jù)綁定到模板列的Label控件中去。而不是像綁定列那樣直接把數(shù)據(jù)綁定到單元格的Text屬性上。
所以取模板列的單元格中的值與取綁定列的單元格中的值是有區(qū)別的:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
//在RowDataBound事件中操作綁定列的單元格中的顯示值
e.Row.Cells[4].Text += "...";
//在RowDataBound事件中操作模板列的單元格中的顯示值
((Label)e.Row.Cells[3].Controls[1]).Text ="...";
}
}
}
在綁定列中,數(shù)據(jù)直接綁定在單元格的Text屬性上,所以可以直接用e.Row.Cells[4].Text進行操作;但在模板列中,數(shù)據(jù)并沒有綁定在單元格的Text上,而是綁定在Label控件的文本上,所以應當通過 e.Row.Cells[3].Controls[1]來取得Label控件(要記得強制轉換)。細心的朋友會發(fā)現(xiàn)這里我是取“當前行第三個單元格中第一個控件”該控件就是顯示數(shù)據(jù)的Label控件,那為什么要取第一個控件而不是第“零”個控件呢?答案是,當GridView運行的時候會在模板列中綁定顯示數(shù)據(jù)的Label控件的前后分別加入一個Literal控件。
下面我們繼續(xù)來解決未解決的問題:(車延祿)
1.如何實現(xiàn)刪除時出現(xiàn)確認提示的功能:
思路:把刪除按鈕所在的列轉換模板列,此時我們就會在“源頁面”中找到刪除按鈕了,然后在刪除按鈕里加入OnClientClick事件,執(zhí)行return window.confirm('...')腳本函數(shù)。
代碼界面:

運行界面:

2.民族列在編輯狀態(tài)下顯示下拉列表
第一步:把民族列變?yōu)槟0辶?br /> 第二步:修改民族列的編輯模板,把原有的文本框刪除,加入下拉列表ddlNation和DataSource控件
第三步:配置DataSource控件,訪問民族字典表。
第四步:將ddlNation下拉列表綁定到DataSource控件上
第五步:打開“源頁面”在ddlNation控件中加入屬性:SelectedValue=<%#Bind('Nation')%>,把下拉列表框的選中值設為當前行的民族值。
運行效果:

大家思考:如何把性別列變?yōu)閱蜗劝粹o列表形式?
3.在編輯狀態(tài)下加入驗證控件:
把在編輯狀態(tài)下需要加入驗證控件的列全都轉換為模板列,然后在其編輯狀態(tài)模板上加入驗證控件,并設置其驗證相應的文本框即可。
4.用模板列實現(xiàn)GridView的嵌套
在GridView模板列的單元格中再加入GridView。這種形式將來有可能用到。
運行效果:
《圖23》
這個例子使用了三個GridView進行嵌套,顯示出制造商、系列和汽車型號之間的關系。
源代碼如下:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
CellPadding="0" DataKeyNames="Prod_code" DataSourceID="ObjectDataSource1"
ForeColor="#333333" GridLines="Horizontal" onrowdatabound="GridView1_RowDataBound"
Width="100%">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#E3EAEB" HorizontalAlign="Center" />
<Columns>
<asp:BoundField DataField="Prod_name" HeaderText="生產(chǎn)廠商"
SortExpression="Prod_name">
<HeaderStyle Width="100px" />
<ItemStyle BackColor="#99CCFF" />
</asp:BoundField>
<asp:TemplateField HeaderText="汽車信息">
<ItemTemplate>
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
CellPadding="0" ForeColor="#333333"
GridLines="Horizontal" ShowHeader="False" Width="100%"
DataKeyNames="Brand_Code" onrowdatabound="GridView2_RowDataBound">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#E3EAEB" BorderStyle="Dotted" HorizontalAlign="Left" />
<Columns>
<asp:BoundField DataField="Brand_name" HeaderText="Brand_name"
SortExpression="Brand_name" >
<HeaderStyle Width="100px" />
<ItemStyle BackColor="#FFCC66" Width="100px" />
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>(車延祿)
<asp:GridView ID="GridView3" runat="server" AutoGenerateColumns="False"
CellPadding="0" ForeColor="#333333" GridLines="None" ShowHeader="False"
Width="100%">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#E3EAEB" />
<Columns>
<asp:BoundField DataField="Name">
<ItemStyle BackColor="#CC99FF" HorizontalAlign="Left" Width="100%" />
</asp:BoundField>
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
</Columns>
...... </asp:GridView>
后臺代碼如下:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
string prodCode = GridView1.DataKeys[e.Row.RowIndex].Value.ToString();
ObjectDataSource sdsBrand = new ObjectDataSource(); ;
sdsBrand.ID = "ObjectDataSource2";
sdsBrand.TypeName = "BrandDA";
sdsBrand.SelectMethod = "selectProd_code";
sdsBrand.SelectParameters.Add("prod_code", prodCode);
e.Row.Cells[1].Controls.Add(sdsBrand);
GridView gvBrand = (GridView)e.Row.Cells[1].FindControl("GridView2");
gvBrand.DataSourceID = sdsBrand.ID;
}
}
}
protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate)
{
GridView gvBrand = e.Row.Parent.Parent as GridView;
ObjectDataSource sdsCar = new ObjectDataSource(); ;
sdsCar.ID = "ObjectDataSource3";
sdsCar.TypeName = "CarDA";
sdsCar.SelectMethod = "selectBrand";
sdsCar.SelectParameters.Add("brand", brandCode);
e.Row.Cells[1].Controls.Add(sdsCar);
GridView gvCar = (GridView)e.Row.Cells[1].FindControl("GridView3");
gvCar.DataSourceID = sdsCar.ID;
}
}
}
五、按鈕列
除了執(zhí)行“命令列”功能之外的其它功能按鈕,這些按鈕在點擊的時候都會觸發(fā)RowCommand事件。如果在GridView中有多個按鈕列,那這多個按鈕列的按鈕就都過來執(zhí)行RowCommand事件中的代碼,如何區(qū)分是哪個按鈕列的哪個按鈕被點擊是一個關鍵性的問題。(車延祿)
區(qū)分不同列的按鈕:
為區(qū)分不同類型的按鈕(即不同列的按鈕),我們在創(chuàng)建按鈕列的時候可以為按鈕列設置CommandName,這樣不同類型的按鈕就可以通過CommandName來區(qū)分了。
區(qū)分不同行的按鈕:
不同行的按鈕不用我們手動區(qū)分,系統(tǒng)會自動為我們區(qū)分,在RowCommand的事件參數(shù)GridViewCommandEventArgs e中有一個屬性e.CommandArgument,它的值就是行的索引號。因此我們可以通過e.CommandArgument判斷是哪一行的按鈕被點擊了。
我們既可以通過按鈕列的CommandName屬性來區(qū)分不同列的按鈕,又可以通過RowCommand事件的GridViewCommandEventArgs參數(shù)取得不同行的按鈕,那二者結合起來使用豈不可以隨意控制頁面中任何地方的按鈕了嗎?
如:
源代碼:
<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1"
onrowcommand="GridView1_RowCommand" DataKeyNames="Ids">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#E3EAEB" />
<Columns>
......
<asp:ButtonField CommandName="cmdUP" Text="向上" />
<asp:ButtonField CommandName="cmdDN" Text="向下" />
</Columns>
......
</asp:GridView>
C#代碼:(車延祿)
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "cmdUP")
{
string pk = GridView1.DataKeys[Convert.ToInt32(e.CommandArgument)].Value.ToString();
Response.Write("主鍵為" + pk + "行的向上按鈕被點擊了");
}
else if (e.CommandName == "cmdDN")
{
string pk = GridView1.DataKeys[Convert.ToInt32(e.CommandArgument)].Value.ToString();
Response.Write("主鍵為" + pk + "行的向下按鈕被點擊了");
}
}