jQuery对话框-回发但UpdatePanel未更新

8

我想在Codebehind中显示一个jQuery UI对话框,并需要在后续请求后刷新它。

该对话框是一个控件,用于过滤和查找数据。因此,用户从DropDownLists中选择并在TextBoxes中输入文本,单击“应用”按钮后会进行异步后台处理,根据用户的选择进行数据过滤,结果将在GridView中显示出来。因此,我需要更新围绕GridView的UpdatePanel。

异步后台处理通过以下链接实现:

(基本上是dlg.parent().appendTo(jQuery("form:first"));解决方案)

问题:我无法使用UpdateMode="Always"或通过UpdatePanel.Update()从Codebehind手动更新UpdatePanel。我认为这可能与对话框不在UpdatePanel内部或类似的事情有关。希望有人能帮助我解决这个问题。

一些源代码:

function createChargeFilterDialog() {
    //setup dialog
    $('#Dialog_ChargeFilter').dialog({
        modal: true,
        resizable: false,
        autoOpen: false,
        draggable: true,
        hide: "Drop",
        width: 850,
        height: 600,
        position: "center",
        title: "Charge-Filter",
        buttons: {
            "Close": function () {
                $(this).dialog("close");
            }
        },
        open: function (type, data) {
            $(this).parent().appendTo(jQuery("form:first"))
        },
        close: function (type, data) {
        }
    });
}

当 BtnShowDialog(在 jQuery-Dialog 之外)被点击时,它会从代码后台调用。

AjaxControlToolkit.ToolkitScriptManager.RegisterStartupScript _
            (Me.Page, GetType(Page), "showChargeFilterDialog", "createChargeFilterDialog();$('#Dialog_ChargeFilter').dialog('open');", True)

更新: 我还注意到了在postback值中的一个问题。所有的TextBoxes,无论是空还是非空,都附加了一个逗号。这表明控件根据http://www.componentart.com/community/forums/t/60999.aspx被多次呈现。

我确定这两个问题是相关的。每次异步postback都会重新创建带有所有控件的对话框,因此DOM中存在多个控件名称(导致ViewState逗号附加问题)。这些控件只在FireBug/IE Developer Toolbar中可见,而不在HTML源代码中,因此我认为是jQuery引起了这些问题。如何销毁对话框或如何防止重建(检查是否已存在)对话框? 这是因为对话框位于UpdatePanel内还是被移动(通过Javascript)到UpdatePanel外?

在异步postback之前销毁对话框并不能解决问题,因为对话框将简单地消失:

<asp:Button ID="BtnApplyFilter" OnClientClick="$('#Dialog_ChargeFilter').dialog('destroy');" ... />

非常感谢您的帮助。


解决方案: 我最终使用了来自AjaxControlToolkit的ModalPopupExtender。 经过一些小问题,它与异步回发一起正常工作(如果您想让弹出窗口保持可见,请不要忘记在每个代码后端函数中调用MPE.Show())。 如果有人感兴趣,我可以添加更多代码。


你好Tim。我有同样的问题。不知道你最终是否找到了潜在的解决方案。我已经在整个应用程序中实现了jquery对话框,但我需要在其中一个对话框中的2个下拉列表之间进行绑定。因此,我将更改为ModalPopUpExtender作为最后的选择。请看一下我的问题:http://stackoverflow.com/questions/8082921/dropdownlist-selected-index-changed-event-inside-jquery-dialog。谢谢。 - aleafonso
4个回答

5
我认为这可能与Dialog不在UpdatePanel内或类似的原因有关。另外,如果所有文本框为空或非空,则已附加逗号。
您的两点都是正确的。问题的关键在于脚本管理器“认为”它应该更新jQuery实际上已将其移动到页面上的其他位置的元素,从而导致多个副本以及您提到的问题。
我曾在使用嵌套的UpdatePanels时遇到过这个问题,但也可能在其他情况下发生。
这是一个需要混乱解决方法的问题。
选项1-更改jQuery UI的源代码。我没有找到一个快速解决方案;除了重写整个插件之外,我找不到一种不会重新排序DOM而使对话框正常工作的简单方法。而且,通过这种方式,现在您“拥有”源代码,因为您已经修改了它。
选项2 - 每当部分呈现页面时调整DOM以删除重复元素。您可以输出一些额外的脚本以清理虚假的重复元素。我不喜欢这种方法,因为它允许DOM处于无效状态,直到运行脚本。
选项3-手动覆盖UpdatePanel的呈现。代码看起来像这样:
private bool _hasDomPresence
{
    get
    {
        return ViewState["__hasDomPresence"] == null ? false : (bool)ViewState["__hasDomPresence"];
    }
    set
    {
        ViewState["__hasDomPresence"] = value;
    }
}

protected override void OnLoad( EventArgs e )
{
    if( !ScriptManager.GetCurrent( this.Page ).IsInAsyncPostBack )
    {
         // a full postback means we no longer have a DOM presence
         _hasDomPresence = false;
    }

    base.OnLoad( e );
}

protected virtual void ShowDetailDialog()
{
    // code to show the offending dialog

    // we are showing it, so note the fact that it now has a DOM presence
    _hasDomPresence = true;
}  

protected override void Render( HtmlTextWriter writer )
{
    foreach( Control c in this.Controls )
    {
        //
        // find the offending control's parent container prior to it being rendered
        // In my scenario, the parent control is just a server-side DIV
        if( c == this.DetailDialog )
        {
            //
            // here, I am checking whether or not the panel actually needs to be
            // rendered. If not, I set it to invisible, thus keeping a new DOM
            // element from being created.
            if( !this.DetailUpdatePanel.IsInPartialRendering && _hasDomPresence )
            {
                this.DetailUpdatePanel.Visible = false;
            }
        }
    }

    base.Render( writer );
}

这还会混淆事件验证,因为客户端和服务器端的页面版本不匹配(或者至少 ASP.Net 无法确定它们是否匹配)。我找到的唯一方法是关闭事件验证。

使用适当的安全模型,事件验证并非必须的,但我不喜欢被迫关闭它。

总之,这是我在 Stack Overflow 上发布的最邪恶的代码,如果您使用它,毛茸茸的小白猫将死亡,但这种方法似乎有效。

希望能对你有所帮助。


感谢您提供的解决方法。但是,与此同时,我已经放弃了jQuery-Dialog方法,并使用了最新的AjaxControlToolkit版本中的ModalPopupExtender。在解决一些较小的问题后,它可以完美地与异步回发一起使用,无论是从客户端还是服务器端打开。再次感谢 :) - Tim Schmelter

4

以下是我解决同样问题的方法。它会删除任何旧对话框并将新更新的对话框添加回表单中,以便后续提交工作。我将以下代码放在通过ScriptManager.RegisterStartupScript在代码后端添加到页面的脚本块中。

$('#divMyDialogAdded').remove();

$('#divMyDialog').dialog({
    autoOpen: false,
    modal: true
}).parent().appendTo('form:first');

$('#divMyDialog').attr('id', 'divMyDialogAdded');

这对我也起作用了,尽管最终我将其放在我的jQuery准备处理程序和pageLoad isPartialLoad处理程序中,而不是使用ScriptManager。 - Nick Sarabyn

1

我不确定,但这可能是正确的答案,因为当我使用时它对我有效。

AjaxControlToolkit.ToolkitScriptManager.RegisterStartupScript

尝试这个吗?
ScriptManager.RegisterClientScriptBlock(Me.Page, GetType(Page), "showChargeFilterDialog", "createChargeFilterDialog();$('#Dialog_ChargeFilter').dialog('open');", True)

谢谢,但那也不起作用。尽管我已经在代码后台进行了更改并调用了 UpdatePanel.Update(),但内容仍然是相同的。 - Tim Schmelter

1
我认为在生成和解析脚本时,Jquery 和脚本管理器/更新面板会发生冲突。您应该正确处理更新面板触发器中的事件,以便在代码后台方法中使用它:
       UpdatePanel2.Update();

我有一个问题,可以通过以下代码解决(这是我的示例代码):

   <!--------- show for dialog --->
<div id="dialog" style="direction: rtl;">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel2" runat="server" RenderMode="Block" UpdateMode="Conditional" EnableViewState="True" ChildrenAsTriggers="True">
        <ContentTemplate>
            <div>
                <table>
                    <tr>
                        <td>
                            <asp:ListBox ID="lstSLA" runat="server" SelectionMode="Single" Width="250px" Height="350px">
                            </asp:ListBox>
                        </td>
                        <td valign="middle">
                            <asp:Button ID="BtnUpMove" runat="server" Text=" top" OnClick="BtnUpMove_Click" />
                            <div>
                                <br />
                            </div>
                            <asp:Button ID="BtnDownMove" runat="server" Text="down" OnClick="BtnDownMove_Click" />
                        </td>
                    </tr>
                    <tr>
                        <td colspan="2" align="center">
                            <asp:Button ID="btnSavePeriority" runat="server" Text="Save" OnClick="btnSavePeriority_Click" />
                        </td>
                        <td>
                        </td>
                    </tr>
                </table>
            </div>
        </ContentTemplate>
        <Triggers>
            <asp:PostBackTrigger ControlID="btnSavePeriority" />
            <asp:AsyncPostBackTrigger ControlID="BtnUpMove" EventName="Click" />
            <asp:AsyncPostBackTrigger ControlID="BtnDownMove" EventName="Click" />
        </Triggers>
    </asp:UpdatePanel>
</div>

以下是C#代码: protected void BtnUpMove_Click(object sender, EventArgs e) { int SelectedIndex = lstSLA.SelectedIndex;

        if (SelectedIndex == -1) // nothing selected
        {
            UpdatePanel2.Update();
            return;
        }
        if (SelectedIndex == 0) // already at top of list  
        {
            UpdatePanel2.Update();
            return;
        }

        ListItem Temp;
        Temp = lstSLA.SelectedItem;

        lstSLA.Items.Remove(lstSLA.SelectedItem);
        lstSLA.Items.Insert(SelectedIndex - 1, Temp);
        UpdatePanel2.Update();
        lstSLA.SelectedIndex = -1;
    }
    protected void BtnDownMove_Click(object sender, EventArgs e)
    {
        int SelectedIndex = lstSLA.SelectedIndex;

        if (SelectedIndex == -1)  // nothing selected  
        {
            UpdatePanel2.Update();
            return;
        }
        if (SelectedIndex == lstSLA.Items.Count - 1)  // already at top of list            
        {
            UpdatePanel2.Update();
            return;
        }

        ListItem Temp;
        Temp = lstSLA.SelectedItem;

        lstSLA.Items.Remove(lstSLA.SelectedItem);
        lstSLA.Items.Insert(SelectedIndex + 1, Temp);
        UpdatePanel2.Update();
        lstSLA.SelectedIndex = -1;

    }
    protected void btnSavePeriority_Click(object sender, EventArgs e)
    {
        if (lstSLA.Items.Count == 0) return;
        try
        {
            var db = DatabaseHelper.GetITILDataAccess();
            ServiceLevel srvlvl = new ServiceLevel();
            int priority = 1;
            foreach (ListItem ls in lstSLA.Items)
            {
                srvlvl = new ServiceLevel();
                srvlvl = db.ServiceLevels.Single(p => p.ID == long.Parse(ls.Value));
                srvlvl.priority = priority;
                priority++;
                ServiceLevelManagement.Update(srvlvl);

            }
            ShowMessage(ITILMessages.InsertComplete);
        }
        catch (Exception ex)
        { }
        finally { }

    }

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