惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Spread Privacy
Spread Privacy
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy & Cybersecurity Law Blog
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
T
Tenable Blog
TaoSecurity Blog
TaoSecurity Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
AI
AI
P
Proofpoint News Feed
A
About on SuperTechFans
P
Privacy International News Feed
月光博客
月光博客
雷峰网
雷峰网
S
Secure Thoughts
博客园 - 叶小钗
博客园 - 聂微东
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Project Zero
Project Zero
The Cloudflare Blog
SecWiki News
SecWiki News
The Hacker News
The Hacker News
V
Vulnerabilities – Threatpost
罗磊的独立博客
A
Arctic Wolf
阮一峰的网络日志
阮一峰的网络日志
Know Your Adversary
Know Your Adversary
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Troy Hunt's Blog
The Last Watchdog
The Last Watchdog
Schneier on Security
Schneier on Security
小众软件
小众软件
有赞技术团队
有赞技术团队
博客园 - 司徒正美
T
Tailwind CSS Blog
量子位
C
Cybersecurity and Infrastructure Security Agency CISA
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
L
Lohrmann on Cybersecurity

博客园 - jeff377

使用 Sandcastle Help File Builder 制作 VS.NET 的 HELP 文件 [ASP.NET 控件实作 Day31] TBContextMenu 控件三种不同模式的 Click 动作 [ASP.NET 控件实作 Day30] 整合 jQuery ContextMenu plugin 的右键选单控件 [ASP.NET 控件实作 Day28] 图形验证码控件 [ASP.NET 控件实作 Day27] 控件依 FormView CurrentMode 自行设定状态 [ASP.NET 控件实作 Day26] 让你的 GridView 与众不同 [ASP.NET 控件实作 Day25] 自订 GridView 字段 - 日期字段 [ASP.NET 控件实作 Day24] TBDropDownField 的 Items 属性的数据系结 [ASP.NET 控件实作 Day23] 自订 GridVie 字段类别 - 实作 TBDropDownField 字段类别 [ASP.NET 控件实作 Day22] 让 DropDownList 不再因项目清单不存在而造成错误 [ASP.NET 控件实作 Day21] 实作控件智能卷标 [ASP.NET 控件实作 Day20] 侦错设计阶段的程序代码 [ASP.NET 控件实作 Day19] 控件设计阶段的外观 [ASP.NET 控件实作 Day18] 修改集合属性编辑器 [ASP.NET 控件实作 Day17] 集合属性包含不同型别的成员 [ASP.NET 控件实作 Day16] 继承 WebControl 实作 Toolbar 控件 [ASP.NET 控件实作 Day15] 复合控件隐藏的问题 [ASP.NET 控件实作 Day14] 继承 CompositeControl 实作 Toolbar 控件 [ASP.NET 控件实作 Day13] Flash 控件
[ASP.NET 控件实作 Day29] 解决 DropDownList 成员 Value 值相同产生的问题
jeff377 · 2008-10-30 · via 博客园 - jeff377

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.SelectedIndexChanged
        Dim sText As String
 
        sText = String.Format("DropDownList: Index={0} Value={1}", DropDownList1.SelectedIndex, DropDownList1.SelectedValue)
        Me.Response.Write(sText)
    End Sub

执行程序,在 DropDownList 选取 "李四" 这个选项时,会正常显示该成员的 SelectedIndex 及 SelectedValue 属性值。

image 

接下来选取 "陈六" 这个选项时,竟然发生奇怪的现象,DorpDownList 竟然显示相同 Value 值的 "王五" 这个成员的 SelectedIndex 及 SelectedValue 属性值。

image image

二、问题发生的原因

我们先看一下 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.EnsureDataBound
    If (Not values Is Nothing) Then
        MyBase.ValidateEvent(postDataKey, values(0))
        Dim selectedIndex As Integer = Me.Items.FindByValueInternal(values(0), False)
        If (Me.SelectedIndex <> selectedIndex) Then
            MyBase.SetPostDataSelection(selectedIndex)
            Return True
        End If
    End If
    Return False
End 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 Boolean
            Dim sScript As String
 
            '記錄 AutoPostBack 值,並將 AutoPostBack 設為 False,不要讓 MyBase 產生 PostBack 的指令碼
            bAutoPostBack = Me.AutoPostBack
            Me.AutoPostBack = False
 
            MyBase.AddAttributesToRender(writer)
 
            If bAutoPostBack Then
                MyBase.Attributes.Remove("onchange")
                sScript = String.Format("__doPostBack('{0}',{1})", Me.ClientID, "this.selectedIndex")
                writer.AddAttribute(HtmlTextWriterAttribute.Onchange, sScript)
                Me.AutoPostBack = True
            End If
        End 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 Boolean
            Dim values As String()
            Dim iSelectedIndex As Integer
 
            Me.EnsureDataBound()
            values = postCollection.GetValues(postDataKey)
 
            If (Not values Is Nothing) Then
                iSelectedIndex = CInt(Me.Page.Request.Form("__EVENTARGUMENT"))
                If (Me.SelectedIndex <> iSelectedIndex) Then
                    MyBase.SetPostDataSelection(iSelectedIndex)
                    Return True
                End If
            End If
            Return False
        End Function

四、测试程序

在 TBDropDownList 的 SelectedIndexChanged 事件撰写如下测试程序代码。

    Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
        Dim sText As String
 
        sText = String.Format("TBDropDownList: Index={0} Value={1}", DropDownList2.SelectedIndex, DropDownList2.SelectedValue)
        Me.Response.Write(sText)
    End Sub

执行程序,在 TBDropDownList 选取 "王五" 这个选项时,会正常显示该成员的 SelectedIndex 及 SelectedValue 属性值。

image

接下选取 Value 值相同的 "陈六" 这个选项,也会正常引发 SelectedIndexChanged ,并显示该成员的 SelectedIndex 及 SelectedValue 属性值。

image

备注:本文同步发布于「第一届iT邦帮忙铁人赛」,如果你觉得这篇文章对您有帮助,记得连上去推鉴此文增加人气 ^^
http://ithelp.ithome.com.tw/question/10013457
http://ithelp.ithome.com.tw/question/10013458