新聞中心
C# DropDownList控件是C#.Net 控件面板Web Form下的一個(gè)控件,通過(guò)預(yù)先設(shè)定或動(dòng)態(tài)數(shù)據(jù)綁定將其填入可供用戶選擇的數(shù)據(jù),既方便了用戶操作,增強(qiáng)軟件的易用性,又能有效的規(guī)范數(shù)據(jù)輸入,成為軟件開(kāi)發(fā)人員最常選擇的控件之一。

創(chuàng)新互聯(lián)專注于西山網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供西山營(yíng)銷型網(wǎng)站建設(shè),西山網(wǎng)站制作、西山網(wǎng)頁(yè)設(shè)計(jì)、西山網(wǎng)站官網(wǎng)定制、微信小程序服務(wù),打造西山網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供西山網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
1.引言
信息和網(wǎng)絡(luò)的發(fā)展,使基于Web應(yīng)用的系統(tǒng)越來(lái)越普及, VS.Net無(wú)疑是開(kāi)發(fā)Web應(yīng)用的系統(tǒng)的最合適的工具之一。但我們?cè)陂L(zhǎng)期的開(kāi)發(fā)實(shí)踐中發(fā)現(xiàn),C#.Net下DropDownList控件在使用過(guò)程中會(huì)遇到一些問(wèn)題,它的SelectedIndex屬性存在一個(gè)讀寫(xiě)缺陷,這個(gè)問(wèn)題也一直困擾著其他的開(kāi)發(fā)人員。因此,本文專門(mén)對(duì)DropDownList做了詳細(xì)的測(cè)試,來(lái)探求問(wèn)題所在和解決辦法。
2.C# DropDownList控件介紹
DropDownList是C#.Net 控件面板Web Form下的一個(gè)控件,它的命名空間是System.Web.UI.WebControls.DropDownList。它是一個(gè)允許用戶從下拉列表中選擇一項(xiàng)的控件,通過(guò)在C# ropDownList 控件的開(kāi)始和結(jié)束標(biāo)記之間為每個(gè)項(xiàng)放置一個(gè)ListItem對(duì)象,可以指定希望顯示在C# DropDownList 控件中的項(xiàng),也支持?jǐn)?shù)據(jù)綁定。DropDownList的功能決定了它在日常開(kāi)發(fā)中的實(shí)用性,在數(shù)據(jù)輸入控件中其使用率僅次于TextBox。通過(guò)預(yù)先設(shè)定或動(dòng)態(tài)數(shù)據(jù)綁定將其填入可供用戶選擇的數(shù)據(jù),既方便了用戶操作,增強(qiáng)軟件的易用性,又能有效的規(guī)范數(shù)據(jù)輸入,成為軟件開(kāi)發(fā)人員最常選擇的控件之一。
3.關(guān)于SelectedIndex的有趣的問(wèn)題
在長(zhǎng)期的使用過(guò)程中我們發(fā)現(xiàn),當(dāng)在程序中動(dòng)態(tài)將DropDownList列表中的某項(xiàng)選定,
或指定SelectedIndex為某一值時(shí),會(huì)出現(xiàn)意想不到的錯(cuò)誤。而使用斷點(diǎn)跟蹤調(diào)試方法或?qū)electedIndex值讀取到某個(gè)變量進(jìn)行測(cè)試,卻難以找到問(wèn)題所在。
3.1 發(fā)現(xiàn)問(wèn)題
假設(shè)有如下簡(jiǎn)單代碼
- private void Page_Load(object sender, System.EventArgs e)
- {
- if (!IsPostBack)
- { //初始化DropDownList下拉列表
- Init_FillList();
- }
- }
- private void btnOK_Click(object sender, System.EventArgs e)
- {
- string strID=txtContinentID.Text.Trim();
- //選擇指定項(xiàng)
- listContinent.Items.FindByValue(strID).Selected=true;
- Response.Write("OK!");
- }
- #region初始化下拉列表方法
- private void Init_FillList()
- { //定義ListItem對(duì)象
- ListItem item;
- //清空列表
- listContinent.Items.Clear();
- //寫(xiě)入列表
- listContinent.Items.Add(" ");
- item=new ListItem("亞洲","Asia");
- listContinent.Items.Add(item);
- item=new ListItem("歐洲","Euro");
- listContinent.Items.Add(item);
- item=new ListItem("美洲","Amer");
- listContinent.Items.Add(item);
- }
- #endregion
把它放到一個(gè)簡(jiǎn)單web頁(yè)面中直接運(yùn)行,在輸入框中輸入大洲編號(hào)Asia,Euro ,Amer中的任一個(gè),點(diǎn)擊btnOK按鈕鍵,看似沒(méi)有任何問(wèn)題的代碼,報(bào)出了如下VS.Net著名的錯(cuò)誤黃頁(yè):(記為:錯(cuò)誤A )
C# DropDownList 不能有多個(gè)項(xiàng)被選定。
說(shuō)明: 執(zhí)行當(dāng)前 Web 請(qǐng)求期間,出現(xiàn)未處理的異常。請(qǐng)檢查堆棧跟蹤信息,以了解有關(guān)該錯(cuò)誤以及代碼中導(dǎo)致錯(cuò)誤的出處的詳細(xì)信息。異常詳細(xì)信息: System.Web.HttpException: DropDownList 不能有多個(gè)項(xiàng)被選定。
通過(guò)認(rèn)真核查代碼并查詢聯(lián)機(jī)幫助,發(fā)現(xiàn)DropDownList的使用符合相關(guān)說(shuō)明文檔的使用方法,沒(méi)有任何問(wèn)題。
為了跟蹤查找錯(cuò)誤的原因,在btnOK_Click()事件下的所有代碼外圍加try…catch保護(hù)進(jìn)行調(diào)試,單步執(zhí)行,發(fā)現(xiàn)一直執(zhí)行到Response.Write("OK!")句,程序都沒(méi)有跳出,繼續(xù)向下,此時(shí)該事件已經(jīng)執(zhí)行完了,沒(méi)有錯(cuò)誤,應(yīng)該顯示出正常的web頁(yè)面,就在這時(shí),上面的錯(cuò)誤黃頁(yè)又出現(xiàn)了。調(diào)試無(wú)法找到錯(cuò)誤所在,如何才能解決這個(gè)問(wèn)題,難道是開(kāi)發(fā)工具的原因,于是想到以下辦法.
3.2 問(wèn)題暫時(shí)解決不能有多個(gè)項(xiàng)被選定,可能是因?yàn)镈ropDownList在選擇新項(xiàng)之前不能自動(dòng)去除原來(lái)的選擇,即,不能有效的對(duì)已添入數(shù)據(jù)的列表進(jìn)行初始化。于是在每次PostBack后將DropDownList的數(shù)據(jù)重新綁定刷新恢復(fù)到系統(tǒng)自己規(guī)定的默認(rèn)值,然后再進(jìn)行新的項(xiàng)的選擇,將Page_Load()事件下的代碼做如下調(diào)整
- private void Page_Load(object sender, System.EventArgs e)
- {
- //去掉 if (!IsPostBack)每次都重寫(xiě)數(shù)據(jù)
- Init_FillList();
- }
此時(shí)再運(yùn)行程序,不再出現(xiàn)錯(cuò)誤A,運(yùn)行正常。但是web應(yīng)用不同于局域網(wǎng)內(nèi)系統(tǒng)的應(yīng)用,它對(duì)程序執(zhí)行效率要求更高,要盡量減少對(duì)服務(wù)器的訪問(wèn)。如果一個(gè)頁(yè)面在每次刷新時(shí)都要重新訪問(wèn)服務(wù)器初始化數(shù)據(jù)地話,會(huì)嚴(yán)重增加服務(wù)器的負(fù)擔(dān)。一旦數(shù)據(jù)量大或訪問(wèn)的終端增多,將會(huì)使頁(yè)面顯示變的非常慢,客戶無(wú)法忍受。需要繼續(xù)尋求其他的解決辦法。
3.3 有趣的bug由于過(guò)去曾經(jīng)長(zhǎng)期從事Delphi下的應(yīng)用系統(tǒng)的開(kāi)發(fā),對(duì)Combox控件的使用非常熟悉,由于他們的功能基本相同,推斷其使用方法應(yīng)該也是有些相通的,于是對(duì)txtOK_Click()進(jìn)行修改,得txtOK2_Click()事件:
- private void txtOK2_Click(object sender, System.EventArgs e)
- {
- string strID=txtContinentID.Text.Trim();
- this.listContinent.SelectedIndex=-1;//新加行
- listContinent.Items.FindByValue(strID).Selected=true;
- Response.Write("OK!");
- }
運(yùn)行程序,果然在加上IsPostBack判斷的情況下,程序仍能正常運(yùn)行。然而這與msdn聯(lián)機(jī)幫助對(duì)DropDownList的使用說(shuō)明是不符的。相關(guān)的屬性說(shuō)明:“DropDownList.SelectedIndex 屬性,DropDownList控件中的選定項(xiàng)的索引。默認(rèn)值為 0,該值選擇列表中的***項(xiàng)。備注 使用 SelectedIndex 屬性以編程方式指定或確定 DropDownList控件中的選定項(xiàng)的索引。DropDownList 控件中總是選擇一項(xiàng)。無(wú)法在列表中同時(shí)取消選擇所有項(xiàng)。注意 DropDownList 控件中的項(xiàng)的索引從零開(kāi)始”。有趣的是不符合使用規(guī)定的程序沒(méi)有報(bào)任何錯(cuò)誤,反而使程序運(yùn)行正常。
為了查看SelectedIndex在運(yùn)行時(shí)的實(shí)際值是0還是1或其他的值,再次跟蹤調(diào)試,此時(shí)發(fā)現(xiàn)了一個(gè)有趣的bug。把斷點(diǎn)設(shè)置到this.listContinent.SelectedIndex=-1行,當(dāng)程序運(yùn)行到這里時(shí)將鼠標(biāo)移到SelectedIndex的位置,查看它的值,(或者通過(guò)開(kāi)發(fā)環(huán)境下邊的變量查看器查看),發(fā)現(xiàn)此時(shí)的值是0,繼續(xù)向下運(yùn)行,錯(cuò)誤A又出現(xiàn)了。而同樣是調(diào)試狀態(tài),單步執(zhí)行代碼,只是不進(jìn)行查看SelectedIndex的操作(通過(guò)變量查看器看也不可以),直到跟蹤完畢,程序運(yùn)行也沒(méi)有問(wèn)題。很明顯,這是C#.Net的一個(gè)bug。
3.4 換一種取值方式既然不能在調(diào)試時(shí)通過(guò)系統(tǒng)的返回值提示查看變量值,只能變通一下,通過(guò)自己定義變量來(lái)獲取SelectedIndex的值。于是對(duì)txtOK2_Click()進(jìn)行修改,得txtOK3_Click()事件:
- private void btnOK3_Click(object sender, System.EventArgs e)
- {
- //新加行 調(diào)試后知 i=0
- int i= listContinent.SelectedIndex;
- string strID=txtContinentID.Text.Trim();
- this.listContinent.SelectedIndex=-1;
- //新加行 調(diào)試后知 j=0
- int j=this.listContinent.SelectedIndex;
- listContinent.Items.FindByValue(strID).Selected=true;
- Response.Write("OK!");
- }
運(yùn)行程序,真正的問(wèn)題出現(xiàn)了,不管在debug狀態(tài)還是非調(diào)試狀態(tài),都是一樣的“DropDownList 不能有多個(gè)項(xiàng)被選定”錯(cuò)誤。這說(shuō)明SelectedIndex的值根本不能進(jìn)行查看或讀取,這也進(jìn)一步證明C#.Net中對(duì)SelectedIndex的讀取實(shí)現(xiàn)代碼有問(wèn)題,存在不安全的判斷。
另外,經(jīng)過(guò)此時(shí)的調(diào)試觀察i和j的返回值是一樣的結(jié)果,這個(gè)結(jié)果也和系統(tǒng)規(guī)定的SelectedIndex的默認(rèn)值為 0一致。這證明了this.listContinent.SelectedIndex=-1這行代碼在txtOK2_Click()中是沒(méi)有起作用沒(méi)有用途的,然而加上該行代碼卻能解決問(wèn)題,使程序正常運(yùn)行。
3.5問(wèn)題根源
通過(guò)反編譯工具和.NET源碼的幫助,找到了C#.Net中關(guān)于DropDownList的源碼實(shí)現(xiàn),發(fā)現(xiàn)了這個(gè)問(wèn)題存在的根源。以下是C#.Net中DropDownList的SelectedIndex屬性源碼實(shí)現(xiàn):
- [WebCategory("Behavior"),DesignerSerializationVisibility
- (DesignerSerializationVisibility.Hidden),DefaultValue(0),
- WebSysDescription("DropDownList_SelectedIndex")]
- public override int SelectedIndex{ get
- { int num1 = base.SelectedIndex;
- if ((num1 < 0) && (this.Items.Count > 0))
- {
- this.Items[0].Selected = true;
- num1 = 0;
- }
- return num1; }
- set
- {
- base.SelectedIndex = value;
- }}
這段源碼實(shí)現(xiàn)表明,在取SelectedIndex時(shí)自動(dòng)進(jìn)行了判斷,只要有數(shù)據(jù)那么Selected的值就肯定大于等于0,所以我們?cè)诓榭磿r(shí)發(fā)現(xiàn)設(shè)置成-1是無(wú)效的,它會(huì)自動(dòng)改為0。另外它還做了另外一部操作this.Items[0].Selected = true,這個(gè)也就是直接導(dǎo)致Exception產(chǎn)生的原因(開(kāi)發(fā)者只是想看看SelectedIndex它就把Item[0]的Selected值給改了...),所以在調(diào)試程序時(shí)要注意回避這個(gè)問(wèn)題,我們只能通過(guò)修改代碼使程序運(yùn)行正常,而無(wú)法改變 VS.NET的源碼實(shí)現(xiàn)。
程序測(cè)試界面,btnOK,btnOK2,btnOK3和列表數(shù)據(jù)綁定代碼的實(shí)現(xiàn)已在上面給出。
4.C# DropDownList結(jié)束語(yǔ)
經(jīng)調(diào)試,在初始設(shè)置SelectedIndex=0的情況下同樣存在“錯(cuò)誤A”的問(wèn)題。而且若將3.3中SelectedIndex=-1改為SelectedIndex=0,此中情況程序不調(diào)試運(yùn)行也會(huì)出現(xiàn)“錯(cuò)誤A”。
在系統(tǒng)對(duì)效率要求不高,數(shù)據(jù)量小的情況下可以采用3.2的方法來(lái)回避這個(gè)問(wèn)題,即每次加載頁(yè)面重新初始化DropDownList列表。也可采取3.3中將SelectedIndex設(shè)為-1的方法來(lái)改進(jìn)這一問(wèn)題,但此時(shí)不要對(duì)SelectedIndex=-1行進(jìn)行單行調(diào)試。兩種方法在工程交付運(yùn)行時(shí)都不會(huì)有任何因?yàn)镾electedIndex而引起的程序錯(cuò)誤。
該文所有測(cè)試在Microsoft .NET Framework 1.1, C# .NET 2003 version 7.1,IE6.0 環(huán)境下編寫(xiě)調(diào)試。
文章名稱:C#DropDownList的一個(gè)有意思的bug及解決
網(wǎng)站URL:http://www.dlmjj.cn/article/cdihgji.html


咨詢
建站咨詢
