网站搜索

javascript - __doPostBack 仅在页面上有 LinkButton、Calendar 或 WizardStep 控件时才有效


我已经发现了 __doPostBack 的一个问题,并找到了一个解决方法。我正在寻找该问题的原因解释和/或比我的解决方法更好的方案。

场景:我有一个下拉菜单,包含以下选项:"-选择-"、"一" 和 "二"。如果用户选择 "一",则执行客户端脚本。如果用户选择 "二",则执行服务器端脚本。

问题:客户端脚本通过调用 __doPostBack 来启动回发。然而,除非页面上还有 LinkButton、Calendar 或 WizardStep 控件,否则实际上不会发生回发。我实际上已经检查了 Visual Studio 工具箱中的所有标准工具并测试了它们。它必须是这三者之一。

解决方法: 添加一个被设置为不显示的 span 包围的链接按钮。

<span style="display:none;">
    <asp:LinkButton ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
</span>

问题:有人能解释这种行为的原因,或者提供一个比我的“解决方法”更好的修复方案吗?

来源 - Javascript(我将它放在了 head 标签之间)

<script language="javascript" type="text/javascript">
    function DropDownList1_change(elementRef) {
        var selectedIndex = elementRef.selectedIndex;
        if (selectedIndex > 0) {
            var selectedValue = elementRef.options[selectedIndex].value;
            if (selectedValue == "One") {
                alert("Because you selected 'One', special javascript code will be executed");
                // Special javascript code goes here
                return;
            }
            else if (selectedValue == "Two") {
                // Special server code gets executed on server DropDownList1_SelectedIndexChanged
                __doPostBack('DropDownList1', '');
            }
        }
    }
</script>

来源 - ASPX 控件

    <asp:DropDownList ID="DropDownList1" runat="server"  onchange="DropDownList1_change(this)" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
        <asp:ListItem>-Select-</asp:ListItem>
        <asp:ListItem>One</asp:ListItem>
        <asp:ListItem>Two</asp:ListItem>
    </asp:DropDownList>
    <br />

    <!-- For some unknown reason __doPostBack only works if there is a LinkButton, Calendar or WizardStep control on the page -->      
    <span style="display:none;">
        <asp:LinkButton ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
    </span>

    Time of last Post Back: <asp:Label ID="Label1" runat="server"></asp:Label><br />
    Time of OnSelectedIndexChanged: <asp:Label ID="Label2" runat="server"></asp:Label>

源代码后台

    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
    }

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
        Label2.Text = DateTime.Now.ToLongTimeString();
    }

附加资源 - 我在发布这个问题后找到了以下文章。这是一篇非常老的微软文章,也是我找到的唯一一篇提到 DropDowns、返回值和回发的具体限制的微软文章。我还没有深入研究他们的解决方案,也不确定是否有时间去研究。主要是发布它,以防我的解决方案在将来失败或对其他人不起作用。

直观上,你可能会认为为 DropDownList 添加确认对话框与为 Button Web 控件添加此类对话框是相同的。也就是说,只需将 DropDownList 的客户端 onchange 属性设置为类似这样的代码:return confirm(...); 使用方式如下:DropDownListID.Attributes("onchange")="return confirm(...);" 不幸的是,这样做不会达到预期效果,因为 AutoPostBack 的 DropDownList 的 onchange 属性会被设置为一段导致回发(postback)的 JavaScript,即调用客户端的 __doPostBack 函数。当你以编程方式自己设置 onchange 属性时,最终结果是渲染出来的客户端 onchange 事件处理程序中既包含你的代码,又包含对 __doPostBack 的调用:

文章很长,所以搜索“带 AutoPostBack 的下拉列表确认”

https://msdn.microsoft.com/en-us/library/aa479302.aspx

答案#1

有两个解决方案。

解决方案 1:比在隐藏的 span 标签周围添加链接按钮更好的解决方法是在页面加载事件中添加以下内容。这可以确保函数 __doPostBack 可用。

protected void Page_Load(object sender, EventArgs e)
{
    Page.ClientScript.GetPostBackEventReference(this, string.Empty);
}

函数 __doPostBack 仅在表单中的控件需要它来执行回发时生成。这包括像 LinkButton 这样的控件以及其他 AutoPostBack 设置为 true 的控件。事实上,只有 Button 和 ImageButton 控件可以在没有 __doPostBack 的情况下执行回发(参见这篇文章)。例如,我们可以在 HTML 输出中看到 LinkButton 是这样呈现的:

<a id="lnk" href="javascript:__doPostBack(&#39;lnk&#39;,&#39;&#39;)">My link</a>


解决方案 2: 以下方法在不使用 __doPostBack 的情况下实现相同的效果。

在本例中,您可以为 DropDownList 设置 AutoPostBack="true":

<asp:DropDownList AutoPostBack="true" onchange="if (!confirmPostBack(this)) return false;" ... >

onchange 事件处理程序在你想要阻止回发时会返回 false。Javascript 函数可以像这样:

function confirmPostBack(ddl)
{
    if (condition) {
        ...
        return true;
    } 
    else {
        ...
        return false;
    }
}

重要:onchange 事件处理程序不应返回任何内容,以便允许回发。你可以使用以下语法:

onchange="if (!confirmPostBack(this)) return false;"

由于可能在问题中提到的文章中解释的原因,以下语法不起作用。返回 true 仍然会阻止回发。

onchange="return confirmPostBack(this);" // Does not work!