什么是异步加载小部件的最佳方法?

时间:2012-01-09 20:39:44

标签: c# jquery asp.net ajax

我正在尝试为我公司的内部网站模拟iGoogle小部件,而且当我回帖时我遇到了问题。我收到的错误是

Sys.WebForms.PageRequestManagerServerErrorException:Sys.WebForms.PageRequestManagerServerErrorException:此页面的状态信息无效,可能已损坏。

单击LayoutButton1按钮时收到此错误。奇怪的是,这个错误发生在IE 9和Chrome 16上,但不是在Firefox 9中。

如何使用我的方法加载ASPX页面或用户控件?我错过了什么吗?有没有更好的方法呢?

这是我想要的行为:

1)用户第一次点击页面并完全加载页面。每个小部件都显示一个ajax loader gif。 2)页面完全加载后,我为每个小部件进行异步调用以加载其内容。每个窗口小部件的内容包含ASP.NET服务器控件,如网格视图控件和树视图控件,因此窗口小部件内容需要是用户控件或ASPX页面。在我的概念验证项目中,我正在使用ASPX页面。 3)检索小部件的内容后,将ajax loader gif替换为我从异步调用中收到的标记。

这是我正在使用的代码。请注意我正在为小部件使用Telerik ASP.NET服务器控件(这不会对我的问题产生任何影响)。

<script type="text/javascript">
    $(document).ready(function ()
    {
        // Wires a client-side click event to the layout buttons.
        $('.layouts').find('input').live('click', function ()
        {
            if ($(this).attr('class') == 'layoutSelected')
            {
                return false;
            }
            else
            {
                return true;
            }
        });
    });

    // Load content of all widgets.
    function loadAllWidgets()
    {
        loadWidget1();
    }

    // Loads widget #1.
    function loadWidget1()
    {
        $(document).ready(function ()
        {
            PageMethods.LoadWidgetContent1(onWidgetContentLoadSucceeded, onWidgetContentLoadFailed);
        });
    }

    // Widget content load success.
    function onWidgetContentLoadSucceeded(result, userContext, methodName)
    {
        switch (methodName)
        {
            case "LoadWidgetContent1":
                $('#Widget1').find('.widgetContent').html(result);
                break;
        }
    }

    // Widget content load fail.
    function onWidgetContentLoadFailed(error, userContext, methodName)
    {
        alert(error);
    }
</script>

<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <div style="padding-bottom: 10px;">
            <table class="layouts">
                <tr>
                    <td>Layout:</td>
                    <td><asp:Button ID="LayoutButton1" CommandArgument="1" OnClick="LayoutButton_Click" runat="server" /></td>
                </tr>
            </table>
        </div>
        <div>
            <telerik:RadDockLayout ID="RadDockLayout1" runat="server">
                <telerik:RadDockZone ID="RadDockZone1" CssClass="dockZone dockZoneWide" runat="server" />
            </telerik:RadDockLayout>
        </div>
    </ContentTemplate>
</asp:UpdatePanel>

protected void LayoutButton_Click(object sender, EventArgs e)
{
    var layoutNumber = Convert.ToInt32(((Button)sender).CommandArgument);

    switch (layoutNumber)
    {
        case 1:
            LayoutButton1.CssClass = "layoutSelected";
            LayoutButton2.CssClass = string.Empty;
            LayoutButton3.CssClass = string.Empty;
            LayoutButton4.CssClass = string.Empty;

            RadDockZone1.CssClass = "dockZone dockZoneWide";
            RadDockZone2.CssClass = "dockZone dockZoneNormal";
            RadDockZone3.CssClass = "dockZone dockZoneNormal";
            RadDockZone4.CssClass = "dockZone dockZoneNormal";
            RadDockZone5.CssClass = "dockZone dockZoneNormal";

            RadDockZone4.Visible = true;
            RadDockZone5.Visible = false;
            CreateWidgets();

            break;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        CreateWidgets();
    }
}

private void CreateWidgets()
{

    var radDock = new RadDock
    {
        Closed = false,
        DefaultCommands = DefaultCommands.All,
        ID = "Widget 1",
        Resizable = false,
        Skin = "Sitefinity",
        Title = "Widget 1",
    };

    var divTag = new HtmlGenericControl("div");
    divTag.Attributes.Add("class", "widgetContent");

    var image = new Image
    {
        CssClass = "ajaxLoader",
        ImageUrl = "~/images/transparent.gif",
        ToolTip = "loading..."
    };

    divTag.Controls.Add(image);
    radDock.ContentContainer.Controls.Add(divTag);
    RadDockLayout1.Controls.Add(radDock);
    radDock.Dock(RadDockZone1);


    ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "LoadAllWidgets", "loadAllWidgets();", true);
}

[WebMethod]
public static string LoadWidgetContent1()
{
    var stringWriter = new StringWriter();
    HttpContext.Current.Server.Execute("~/WidgetContent/WidgetContent1.aspx", stringWriter);
    return stringWriter.ToString();
}

2 个答案:

答案 0 :(得分:1)

好的 - 经过几个小时和多个方法,我认为我找到了一个很好的解决方案。我发现工作的解决方案是使用用户控件而不是ASPX页面。这将允许服务器标签并防止我遇到的无效视图状态问题。我需要在代码隐藏中进行的唯一更改是更新Web方法,如下所示:

[WebMethod]
public static string LoadWidgetContent()
{
    Page pageHolder = new Page();
    UserControl viewControl = (UserControl)pageHolder.LoadControl("~/WidgetContent/WidgetContent.ascx");
    pageHolder.Controls.Add(viewControl);

    StringWriter output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);

    return output.ToString();
}

这种方法允许我继续使用更新面板,并在页面完全加载后加载小部件。 I ended up using Scott Gu's blog as a reference。这有点过时,但使用Web方法的基本原则仍然存在。

答案 1 :(得分:0)

您使用的方法是正确的,可以正常工作。如果您需要专业小部件的示例 - 请查看Telerik Sitefinity。该产品是商业版,但您可以下载试用版并进行测试。