简体   繁体   English

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

[英]What's The Best Way To Load Widgets Asynchronously?

I'm trying to emulate iGoogle widgets for my company's internal website and I'm running into a problem when I do a post back. 我正在尝试为我公司的内部网站模拟iGoogle小部件,当我回帖时我遇到了问题。 The error I receive is 我收到的错误是

Sys.WebForms.PageRequestManagerServerErrorException: Sys.WebForms.PageRequestManagerServerErrorException: The state information is invalid for this page and might be corrupted. Sys.WebForms.PageRequestManagerServerErrorException:Sys.WebForms.PageRequestManagerServerErrorException:状态信息对于此页面无效,可能已损坏。

I receive this error when the LayoutButton1 button is clicked. 单击LayoutButton1按钮时收到此错误。 The weird thing is that this error occurs on IE 9 and Chrome 16, but not in Firefox 9. 奇怪的是,这个错误发生在IE 9和Chrome 16上,但不是在Firefox 9中。

How can I load ASPX pages or user controls using my approach? 如何使用我的方法加载ASPX页面或用户控件? Am I missing something? 我错过了什么吗? Is there a better way of doing this? 有没有更好的方法呢?

Here the desired behavior I want to have: 这是我想要的行为:

1) The user hits the page the first time and the page fully loads. 1)用户第一次点击页面并完全加载页面。 Each widget displays an ajax loader gif. 每个小部件都显示一个ajax loader gif。 2) After the page fully loads, I make asynchronous calls for each widget to load their content. 2)页面完全加载后,我为每个小部件进行异步调用以加载其内容。 The content of each widget contains ASP.NET server controls like grid view controls and tree view controls, so the widget content needs to be a user control or an ASPX page. 每个窗口小部件的内容包含ASP.NET服务器控件,如网格视图控件和树视图控件,因此窗口小部件内容需要是用户控件或ASPX页面。 In my proof of concept project, I'm using ASPX pages. 在我的概念验证项目中,我正在使用ASPX页面。 3) After the content of the widget is retrieved, the the ajax loader gif is replaced with the markup I received from the asynchronous call. 3)在检索小部件的内容之后,将ajax loader gif替换为我从异步调用接收的标记。

Here is the code I'm using. 这是我正在使用的代码。 Please note I'm using Telerik ASP.NET server controls for the widgets (which shouldn't have any influence on my problem). 请注意我正在为小部件使用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();
}

OK - after several hours and multiple approaches to this, I think I've found a good solution. 好的 - 经过几个小时和多个方法,我想我找到了一个很好的解决方案。 The solution I found to work is to use user controls instead of ASPX pages. 我发现工作的解决方案是使用用户控件而不是ASPX页面。 This will allow for server tags and prevents the invalid view state issue I was having. 这将允许服务器标签并防止我遇到的无效视图状态问题。 The only change I needed to make in the code-behind was to update the web method like so: 我需要在代码隐藏中进行的唯一更改是更新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();
}

This approach allowed me to continue using the update panel and loaded the widgets once the page was completely loaded. 这种方法允许我继续使用更新面板并在页面完全加载后加载小部件。 I ended up using Scott Gu's blog as a reference . 我最终使用Scott Gu的博客作为参考 This is a bit outdated, but the basic principle of using web methods still holds. 这有点过时,但使用Web方法的基本原则仍然存在。

The approach you are using is correct and could work. 您使用的方法是正确的,可以工作。 If you need an example of professional widgets - take a look at the Telerik Sitefinity. 如果您需要专业小部件的示例 - 请查看Telerik Sitefinity。 The product is commercial, but you can download a Trial version and test it. 该产品是商业版,但您可以下载试用版并进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM