jQuery对话框与ASP.NET UpdatePanel的“关闭”冲突

5

我有一个包含以下内容的ASP.NET UpdatePanel:

<asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
    <%-- jQuery dialog - Suppliers --%>
    <div id="divSuppliers" style="display: none;">
        <asp:ListBox ID="lstSuppliers" runat="server" SelectionMode="Single" Rows="10" Width="100%"
            DataValueField="SupplierID" DataTextField="SupplierName">
        </asp:ListBox>
        <br /><br />
        <asp:Button ID="btnSelectSupplier" runat="server" Text="Select 2" OnClick="btnSelectSupplier_Click" />
    </div>

    <asp:GridView ID="gvSuppliers" runat="server" AutoGenerateColumns="false" SkinID="gvSkin"
        DataKeyNames="SupplierID" EmptyDataText="No Existing User Roles">
        <Columns>
            <asp:TemplateField HeaderText="Supplier Name">
                <ItemTemplate>
                    <asp:Label ID="lblSupplierName" runat="server" Text='<%# Eval("SupplierName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

    <asp:Button ID="btnAddSupplier" runat="server" Text="Add Supplier" 
        Visible="false" OnClick="btnAddSupplier_Click" />

</ContentTemplate>
<Triggers>
    <asp:AsyncPostBackTrigger ControlID="btnSelectSupplier" />
</Triggers>
</asp:UpdatePanel>

非常简单,就是一个我用于jQuery对话框弹出的div,一个只有一列的ASP.NET GridView控件和一个用于异步Postback的ASP.NET按钮。

这是处理btnSelectSupplier异步Postback的点击事件。

protected void btnSelectSupplier_Click(object sender, EventArgs e) {

    // +=+=+=+=+=+=+=+=+=+=+=+=+=+=    
    // WORKS JUST FINE
    List<SupplierItem> suppliers = new List<SupplierItem>();    

    foreach (int i in lstSuppliers.GetSelectedIndices()) {
        suppliers.Add(
            new SupplierItem { SupplierID = Convert.ToInt32(lstSuppliers.Items[i].Value), SupplierName = lstSuppliers.Items[i].Text });
        lstSuppliers.Items[i].Selected = false;
    }

    gvSuppliers.DataSource = suppliers;
    gvSuppliers.DataBind();

    // +=+=+=+=+=+=+=+=+=+=+=+=+=+=
    // DOES NOT WORK!!
    string jq = "$('#divSuppliers').dialog('close');";

    ScriptManager sm = ScriptManager.GetCurrent(this);
    if (sm != null && sm.IsInAsyncPostBack) {
        ScriptManager.RegisterClientScriptBlock(
            this, typeof(Page), Guid.NewGuid().ToString(),
            jq, true);
    }
}

问题: GridView在异步回发期间可以正常更新(请参见上面的单击事件);然而,jQuery对话框拒绝关闭(再次请参见上面的事件和“不起作用”的位置)。我在页面上使用ScriptManager注册了javascript(jquery),因此它应该执行并关闭对话框,但出于某种原因它没有。

编辑: 打开jQuery对话框并使其模态的代码。

protected void btnAddSupplier_Click(object sender, EventArgs e) {
    lstSuppliers.ClearSelection();
    lstSuppliers.DataSource = Suppliers.GetAllSuppliers();
    lstSuppliers.DataBind();

    string jq = "var dlg = $('#divSuppliers').dialog({ modal: true, draggable: true, title: 'Suppliers', width: 500 }); dlg.parent().appendTo($('form:first'));";

    ScriptManager sm = ScriptManager.GetCurrent(this);
    if (sm != null && sm.IsInAsyncPostBack) {
        ScriptManager.RegisterClientScriptBlock(
            this, typeof(Page), Guid.NewGuid().ToString(),
            jq, true);
    }
}

你能展示你的jQuery代码吗?我可以解决这个问题。 - Thulasiram
我的代码中只包含了相关的jQuery(请参见点击事件代码)。对话框关闭出现了问题 - 就是这样。 - Jagd
你尝试过在JS控制台(如Firebug或Safari/Chrome的开发者控制台)中执行$('#divSuppliers').dialog('close');吗? - Kyle Macey
你的页面包含jQuery UI库,对吗? - Surreal Dreams
3个回答

2
jQuery UI Dialog所使用的div应该放在UpdatePanel之外。
在btnAddSupplier_Click中,您创建了对话框并将其移动到UpdatePanel之外。
在btnSelectSupplier_Click后,您有两个具有divSuppliers id的div,一个是移动的,另一个是从服务器接收的(UpdatePanel机制通过使用从服务器返回的html重建整个UpdatePanel DOM来允许部分页面更新)。
我还建议使用console.log来帮助调试。
在关闭对话框的js中添加:console.log($('#divSuppliers'))

你关于将jQuery对话框移出updatepanel可能是正确的。实际上,我一开始就是这样做的,但由于某些原因我不记得了,我把它移到了updatepanel内部。如果没有理由,我不会把它移到那里的。无论如何,我需要进行更多测试,看看是否能在有额外时间时工作。我仍然认为我只需剥离.net垃圾,改用jQuery和AJAX即可。 - Jagd
当更新面板被更新时,它的整个HTML都会被删除并用从服务器接收到的内容更新,包括对话框div,因此你会得到两个具有相同ID的div,一个是你移动到外面的,另一个是从更新面板更新中重新创建的。 - eitanpo
你应该在更新面板之外创建一个新的空的 divSuppliersDialog,并将其用于对话框。在显示它之前,你需要使用 RegisterClientScriptBlockdivSuppliers 移动为 divSuppliersDialog 的子元素(就像你已经做过的那样)。 - eitanpo
UpdatePanel是一个非常重的机制。使用jQuery ajax代替UpdatePanel将是一个明智的选择。我建议在下一个项目中尝试ASP.NET MVC - eitanpo
我知道.NET的AJAX解决方案(脚本管理器和更新面板)与jQuery的区别。虽然.NET的解决方案会带来更多的开销,但实现起来可能更简单。在我的经验中,使用jQuery AJAX需要更多的设置时间。关于ASP.NET MVC,我意识到它比Web应用程序更适合jQuery,但这一事实本身并不意味着人们应该仅仅因为使用jQuery就使用MVC而不是Web应用程序。感谢您的帮助。 - Jagd

1
你有没有考虑采用更简单的方法,绑定一个事件到按钮客户端来关闭对话框?
 $(function () {
    $('#btnSelectSupplier').click(function () {

        $('#divSuppliers').dialog('close');
    });
});

从用户角度来看,流程仍然是相同的。他们点击按钮,对话框关闭。服务器端代码将在对话框关闭后运行,但由于似乎没有任何服务器端逻辑决定您是否想要在单击后关闭对话框,因此这可能符合您的需求。

编辑 我看到了你的问题。你遇到了一个问题,因为你不是打开现有的对话框,而是在单击时重新定义了对话框:

 string jq = "var dlg = $('#divSuppliers').dialog({ modal: true, draggable: true, title: 'Suppliers', width: 500 }); dlg.parent().appendTo($('form:first'));";

相反,您希望在document.ready函数中定义对话框。

 $(function () {
    //define the div as a dialog. By default, it will not open until you tell it to
$('#divSuppliers').dialog({ modal: true, draggable: true, title: 'Suppliers', width: 500 });

});

点击时,应该像这样打开

 $('#divSuppliers').dialog('open');

再次提醒,您可能希望在客户端执行此操作,而不是尝试将脚本推送到服务器端事件中,但这取决于您。

最简单的完整解决方案:

$(function () {

$('#divSuppliers').dialog({ modal: true, draggable: true, title: 'Suppliers', width: 500 });

$('#btnAddSupplier').click(function () {

    $('#divSuppliers').dialog('close');
});
$('#btnSelectSupplier').click(function () {

    $('#divSuppliers').dialog('open');
});
});

这个可以工作,但只有第一次单击btnSelectSupplier时有效。如果我重新打开对话框(通过单击不同的按钮完成),然后再次单击btnSelectSupplier,它就无法关闭对话框了。我在btnSelectSupplier单击事件中放置了一个警报,以确保每次单击按钮时都会引发它,而警报确实显示出来了。就好像jquery对话框的div在第一次关闭后就找不到了。 - Jagd
在看到你的更新后,我更新了我的答案。你在点击时重新定义了对话框,而不是调用.dialog('open')函数。 - Rondel

0
所以这里的解决方案是:不要试图将ASP.NET UpdatePanel与jQuery Dialog混合使用,因为它们之间并不兼容。
我之所以采用这种方法,是因为我认为使用.NET的ScriptManager和UpdatePanel控件来放置AJAX会比在jQuery中完成所有工作更省时间。但现在看来,我错了,因为我正在回头拆除.NET垃圾并全部替换为jQuery。所以我原本以为可以节省的所有时间都像风一样消失了。
故事的寓意是:如果没有必要,就不要混合使用两者。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接