- 你所在位置:首页 〉VS.net〉ASP.net〉控件〉[ASP.NET 控件实作] 解决 DropDownList 成员 Value 值相同产生的问题
- [ASP.NET 控件实作] 解决 DropDownList 成员 Value 值相同产生的问题
- 作者:jeff377 文章来源:博客园 发布日期:2008-10-31 浏览次数:60
-
- 打印这篇文章
-
DropDownList 控制页的成员清单中,若有 ListItem 的 Value 值是相同的情形时,会造成 DropDownList 无法取得正确的 SelectedIndex 属性值、且无法正确引发 SelectedIndexChanged 事件的问题;今天刚好在网络上看到有人在询问此问题,所以本文将说明这个问题的源由,并修改 DropDownList 控件来解决这个问题。
程序代码下载:ASP.NET Server Control - Day29.rar
一、DropDownList 的成员 Value 值相同产生的问题
我们先写个测试程序来描述问题,在页面上放置一个 DropDownList 控件,设定 AutoPostBack=True,并加入四个 ListItem,其中 "王五" 及 "陈六" 二个 ListItem 的 Value 值相同。
〈asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">〈asp:ListItem Value="0">張三〈/asp:ListItem>〈asp:ListItem Value="1">李四〈/asp:ListItem>〈asp:ListItem Value="2">王五〈/asp:ListItem>〈asp:ListItem Value="2">陳六〈/asp:ListItem>〈/asp:DropDownList>在 DropDownList 的 SelectedIndexChanged 事件,输出 DropDownList 的 SelectedIndex 及 SelectedValue 属性值。
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChangedDim sText As StringsText = String.Format("DropDownList: Index={0} Value={1}", DropDownList1.SelectedIndex, DropDownList1.SelectedValue)Me.Response.Write(sText)End Sub执行程序,在 DropDownList 选取 "李四" 这个选项时,会正常显示该成员的 SelectedIndex 及 SelectedValue 属性值。
接下来选取 "陈六" 这个选项时,竟然发生奇怪的现象,DorpDownList 竟然显示相同 Value 值的 "王五" 这个成员的 SelectedIndex 及 SelectedValue 属性值。
二、问题发生的原因
我们先看一下 DropDownList 输出到客户端的 HTML 原始码。
〈select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1">
〈option selected="selected" value="0">張三〈/option>〈option value="1">李四〈/option>〈option value="2">王五〈/option>〈option value="2">陳六〈/option>〈/select>
DropDownList 是呼叫 __doPostBack 函式,只传入 eventTarget参数 (对应到 __EVENTTARGET 这个 HiddenField) 为 DropDownList 的 ClientID;当 PostBack 回伺服端时,在 DropDownList 的 LoadPostData 方法中,会取得客户端选取的 SelectedValue 值,并去寻找对应的成员的 SelectedIndex 值。可是问题来了,因为 "王五" 与 "陈六" 的 Value 是相同的值,当在寻找符合 Value 值的成员时,前面的选项 "王五" 会先符合条件而传回该 Index 值,所以先造成取得错误的 SelectedIndex 。
Protected Overridable Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As Boolean
Dim values As String() = postCollection.GetValues(postDataKey)Me.EnsureDataBoundIf (Not values Is Nothing) ThenMyBase.ValidateEvent(postDataKey, values(0))Dim selectedIndex As Integer = Me.Items.FindByValueInternal(values(0), False)If (Me.SelectedIndex 〈> selectedIndex) ThenMyBase.SetPostDataSelection(selectedIndex)Return TrueEnd IfEnd IfReturn FalseEnd Function三、修改 DropDownList 控件来解决问题
要解决这个问题最好的方式就是直接修改 DropDownList 控件,自行处理前端呼叫 __doPostBack 的动作,将客户端 DropDownList 选择 SelectedIndex 一并传回伺服端。所以我们继承 DropDownList 命名为 TBDropDownList,覆写 AddAttributesToRender 来自行输出 PostBack 的客户端指令码,我们会用一个变量记录 AutoPostBack 属性,并强制将 AutoPostBack 属性值设为 False,这是为了不要 MyBase 产生 PostBack 的指令码;然后再自行输出 AutoPostBack 客户端指令码,其中 __doPostBack 的 eventArgument 参数 (对应到 __EVENTARGUMENT 这个 HiddenField) 传入 this.selectedIndex。
Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)Dim bAutoPostBack As BooleanDim sScript As String'記錄 AutoPostBack 值,並將 AutoPostBack 設為 False,不要讓 MyBase 產生 PostBack 的指令碼bAutoPostBack = Me.AutoPostBackMe.AutoPostBack = FalseMyBase.AddAttributesToRender(writer)If bAutoPostBack ThenMyBase.Attributes.Remove("onchange")sScript = String.Format("__doPostBack('{0}',{1})", Me.ClientID, "this.selectedIndex")writer.AddAttribute(HtmlTextWriterAttribute.Onchange, sScript)Me.AutoPostBack = TrueEnd IfEnd Sub在页面上放置一个 TBDropDownList 控件,设定与上述案例相同的成员清单。
〈bee:TBDropDownList ID="DropDownList2" runat="server" AutoPostBack="True">〈asp:ListItem Value="0">張三〈/asp:ListItem>〈asp:ListItem Value="1">李四〈/asp:ListItem>〈asp:ListItem Value="2">王五〈/asp:ListItem>〈asp:ListItem Value="2">陳六〈/asp:ListItem>〈/bee:TBDropDownList>执行程序查看 TBDropDownList 控件的 HTML 原始码,呼叫 __doPostBack 函式的参数已经被修改,eventArgument 参数会传入该控件的 selectedIndex。
〈select name="DropDownList2" id="DropDownList2" onchange="__doPostBack('DropDownList2',this.selectedIndex)">
〈option selected="selected" value="0">張三〈/option>〈option value="1">李四〈/option>〈option value="2">王五〈/option>〈option value="2">陳六〈/option>〈/select>
接下来还要覆写 LoadPostData 方法,取得 __EVENTARGUMENT 这个 HiddenField 的值,并判断与原 SelectedIndex 属性值是否不同,不同的话传回 True,使其产生 SelectedIndexChanged 事件。
Protected Overrides Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As BooleanDim values As String()Dim iSelectedIndex As IntegerMe.EnsureDataBound()values = postCollection.GetValues(postDataKey)If (Not values Is Nothing) TheniSelectedIndex = CInt(Me.Page.Request.Form("__EVENTARGUMENT"))If (Me.SelectedIndex 〈> iSelectedIndex) ThenMyBase.SetPostDataSelection(iSelectedIndex)Return TrueEnd IfEnd IfReturn FalseEnd Function四、测试程序
在 TBDropDownList 的 SelectedIndexChanged 事件撰写如下测试程序代码。
Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChangedDim sText As StringsText = String.Format("TBDropDownList: Index={0} Value={1}", DropDownList2.SelectedIndex, DropDownList2.SelectedValue)Me.Response.Write(sText)End Sub执行程序,在 TBDropDownList 选取 "王五" 这个选项时,会正常显示该成员的 SelectedIndex 及 SelectedValue 属性值。
接下选取 Value 值相同的 "陈六" 这个选项,也会正常引发 SelectedIndexChanged ,并显示该成员的 SelectedIndex 及 SelectedValue 属性值。
- 打印这篇文章
- 与本文主题相关的文章
-
- 返回首页
