c# - ASP.NET 双列表框使用 JQuery 更新了客户端,以及如何在服务器端检索结果

标签 c# javascript jquery asp.net webforms

我一直在尝试启动并运行具有双列表框的 ASP.NET WebForms 页面。这是一个标准范例,其中有两个并排的列表框,左侧有可用项目,右侧有选定项目,还有用于将项目从一侧移动到另一侧的按钮。

我希望所有工作都在客户端通过 JQuery(或其他)完成。我希望能够在回发时检索选定的项目。

我遇到过各种各样的障碍。这里有一些:

1) 当回发发生时,我收到此错误:

Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

关闭“EnableEventValidation”是有风险的。但是“ClientScriptManager.RegisterForEventValidation”令人困惑。

2) 假设我到了真正让回发发生的地步,我的列表框不包含所选项目。

一个常见的推荐解决方案是在回发之前将所选值复制到隐藏字段中。严重地?一定有更好的方法。

3) 当然,关于客户端脚本应该如何工作的所有细节也令人困惑,尽管没有前两项那么糟糕。

那么解决方案是什么?我已经在下面发布了答案。

最佳答案

根据 https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ , 不仅可以提出并回答您自己的问题,而且受到鼓励。这就是我正在做的。

这是我的工作解决方案,之后我将详细介绍。请注意,我绝不是 Web 开发或 Javascript 方面的专家——远非如此。因此,对所有这些持保留态度,并永远记住,如果您的代码以某种方式设法执行 HCF 代码,我概不负责。

<script>
    function addAllItems() {
        $("#<%= lbAvail.ClientID %> option").appendTo("#<%= lbSelected.ClientID %>");
        enableControls();
    }

    function addSelectedItems() {
        $("#<%= lbAvail.ClientID %> option:selected").appendTo("#<%= lbSelected.ClientID %>");
        enableControls();
    }

    function removeAllItems() {
        $("#<%= lbSelected.ClientID %> option").appendTo("#<%= lbAvail.ClientID %>");
        enableControls();
    }

    function removeSelectedItems() {
        $("#<%= lbSelected.ClientID %> option:selected").appendTo("#<%= lbAvail.ClientID %>");
        enableControls();
    }

    function enableButtons(listBoxControlId, buttonAllControlId, buttonSelectedContolId) {
        var count = $("#" + listBoxControlId + " option").length;
        document.getElementById(buttonAllControlId).disabled = count <= 0;

        count = $("#" + listBoxControlId + " option:selected").length;
        document.getElementById(buttonSelectedContolId).disabled = count <= 0;
    }

    function enableControls() {
        enableButtons("<%= lbAvail.ClientID %>", "<%= btnAddAll.ClientID %>", "<%= btnAddSelected.ClientID %>");
        enableButtons("<%= lbSelected.ClientID %>", "<%= btnRemoveAll.ClientID %>", "<%= btnRemoveSelected.ClientID %>");
    }

    function selectAll() {
        $("#<%= lbSelected.ClientID %> option").prop("selected", true);
    }
</script>

<div style="margin-top: 20px;">
    <table>
        <tr>
            <td>
                <asp:ListBox ID="lbAvail" runat="server" style="min-width: 150px" Height="150" SelectionMode="Multiple" 
                             onchange="enableControls();" ondblclick="addSelectedItems();"/>
            </td>
            <td style="padding-left: 10px; padding-right: 10px;">
                <table>
                    <tr>
                        <td>
                            <asp:Button Width="35" ID="btnAddAll" Text="&raquo;" OnClientClick="addAllItems(); return false;" UseSubmitBehavior="False" runat="server"/>
                        </td>
                    </tr>
                    <tr>
                        <td style="padding-top: 5px">
                            <asp:Button Width="35" ID="btnAddSelected" Text=">" OnClientClick="addSelectedItems(); return false;" UseSubmitBehavior="False" runat="server"/>
                        </td>
                    </tr>
                    <tr>
                        <td style="padding-top: 5px">
                            <asp:Button Width="35" ID="btnRemoveSelected" Text="<" OnClientClick="removeSelectedItems(); return false;" UseSubmitBehavior="False" runat="server"/>
                        </td>
                    </tr>
                    <tr>
                        <td style="padding-top: 5px">
                            <asp:Button Width="35" ID="btnRemoveAll" Text="&laquo;" OnClientClick="removeAllItems(); return false;" UseSubmitBehavior="False" runat="server"/>
                        </td>
                    </tr>
                </table>
            </td>
            <td>
                <asp:ListBox ID="lbSelected" runat="server" style="min-width: 150px" Height="150" SelectionMode="Multiple"
                             onchange="enableControls();" ondblclick="removeSelectedItems();"/>
            </td>
        </tr>
    </table>
    
    <div style="margin-top: 10px;">
        <asp:Button ID="btnSubmit" CssClass="btn btn-primary" Text="Submit" runat="server" OnClientClick="selectAll();"/>
    </div>
</div>

...

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        lbAvail.Items.Add(new ListItem("Monday", "Mon"));
        lbAvail.Items.Add(new ListItem("Tuesday", "Tues"));
        lbAvail.Items.Add(new ListItem("Wednesday", "Wed"));
        lbAvail.Items.Add(new ListItem("Thursday", "Thur"));
        lbAvail.Items.Add(new ListItem("Friday", "Fri"));
        lbAvail.Items.Add(new ListItem("Saturday", "Sat"));

        lbSelected.Items.Add(new ListItem("Sunday", "Sun"));

        ScriptManager.RegisterStartupScript(this, GetType(), "CallEnableControls", "enableControls()", true);
    }
    else
    {
        string[] selectedValues = Request.Form.GetValues(lbSelected.UniqueID);
        // ...
    }
}

protected override void Render(HtmlTextWriter writer)
{
    // Register all Available items as valid items in the Selected listbox.
    foreach (ListItem item in lbAvail.Items)
    {
        ClientScript.RegisterForEventValidation(lbSelected.UniqueID, item.Value);
    }

    // When a user removes an item from the Selected listbox, we put it into the
    // Available listbox, so we have to register it here, or we'll get an error.
    foreach (ListItem item in lbSelected.Items)
    {
        ClientScript.RegisterForEventValidation(lbAvail.UniqueID, item.Value);
    }

    base.Render(writer);
}

这里有一些解释:

还记得我在将项目从一个列表框移动到另一个列表框然后发布页面后遇到的“无效回发或回调参数”错误吗?这个错误实际上是一个线索,表明 ASP.NET 确实在回发数据中包含修改后的列表框内容。

为了访问修改后的列表框项目,我们只需要这一行:

string[] selectedValues = Request.Form.GetValues(lbSelected.UniqueID);

这为我们提供了选定列表框中值的数组。我们不需要使用隐藏字段或文本框或其他任何东西。既然数据被发回给我们,我们不妨使用它。请注意,这些是值,而不是显示字符串。

一个重要提示:只有列表框中的选定项目会被发回。所以在标记代码中,您会看到当单击提交按钮时,我调用了一些 javascript 代码来选择选定列表框中的所有项目(我不关心可用列表框中的内容)。

那么我们如何防止“无效的回发或回调参数”错误,这样我们才能真正使用这些数据呢?我们必须告诉 ASP.NET 哪些值对每个列表框有效。我们在“Render()”方法中使用“ClientScript.RegisterForEventValidation”来执行此操作。

ASP.NET 已经知道我们最初放置在每个列表框中的值是要返回的有效值。所以我们所要做的就是注册其他可能返回的值。这就是我在上面的“注册”方法中所做的。

至于 Javascript 代码,应该是不言自明的。请记住,它实际上是在调用一些 JQuery 函数,因此您显然必须包含 Jquery。

希望对您有所帮助。我花了一段时间才弄明白,就像我说的,我找不到一个地方有所有的答案。当然,一旦我发布此信息,就会有 15 个人指出我本可以轻松找到此信息的位置,但这就是生活。

关于c# - ASP.NET 双列表框使用 JQuery 更新了客户端,以及如何在服务器端检索结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24293744/

相关文章:

JQuery inArray 显示选择图像的顺序

c# - 如何从文件名获取完整文件路径?

javascript - 函数式javascript?

javascript - 像 Javascript 一样通过字符串名称调用 Java 函数

javascript - 如何正确自动滚动到滚动条的末尾?

javascript - 隐藏 10000 个下拉菜单的最佳方法

c# - 是否可以通过编程方式设置 MasterType?

c# - 如何将用户控件作为 ListBoxItem

c# - .net 异常捕获 block

javascript - jQuery:函数如何仅通过点 (.) 工作