ASP.Net: 两个Update Panel实现异步加载

9
我正在尝试在一个网站上异步显示数据,其中数据检索任务需要不同的时间。我想在每个任务完成后更新每个面板以显示页面上的数据。
然而,无论我尝试什么,所有的UpdatePanel都会在最后一个任务完成后更改它们的内容。
例如:
我有两个任务:
一个任务在5秒后尝试更新UpdatePanel1中的标签
一个任务在10秒后尝试更新UpdatePanel2中的标签
预期结果是只有UpdatePanel1中的标签在5秒后更改,但是,两个更新面板都在10秒时同时更新。
两个更新面板均设置为updatemode="Conditional",并且告诉它们从客户端JavaScript进行postback。下面是上述示例的完整列表。
我错过了什么?我如何使一个更新面板加载,然后是另一个更新面板,让两个任务异步运行?
谢谢,
TM
ASPX:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"
    Inherits="_Default"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body onload="partialPostback();">
    <script language="JavaScript" type="text/javascript">

    function partialPostback() {
        __doPostBack('UpdatePanel1', '');
        __doPostBack('UpdatePanel2', '');
    }
    </script>

    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server"/>

        5 sec:
        <asp:UpdatePanel ID="UpdatePanel1" runat="server"
         UpdateMode="Conditional" OnLoad="UpdatePanel1_Load">
            <ContentTemplate>
                <asp:Label ID="Label2" runat="server" Text="Label"/><br />
            </ContentTemplate>
        </asp:UpdatePanel><br />

        10 sec:
        <asp:UpdatePanel ID="UpdatePanel2" runat="server"
         UpdateMode="Conditional" OnLoad="UpdatePanel2_Load">
            <ContentTemplate>
                <asp:Label ID="Label1" runat="server" Text="Label"/><br />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

public partial class _Default : System.Web.UI.Page
{
    Thread t1;
    Thread t2;

    protected override void OnPreRender(EventArgs e)
    {
        if (t1 != null)
        { t1.Join(); }

        if (t2 != null)
        { t2.Join(); }

        base.OnPreRender(e);
    }

    protected void Page_Load(object sender, EventArgs e)
    { }

    protected void UpdatePanel1_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            ThreadStart tstart = new ThreadStart(DoWork1);
            t1 = new Thread(tstart);
            t1.IsBackground = true;
            t1.Start();
        }
    }

    protected void UpdatePanel2_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            ThreadStart tstart = new ThreadStart(DoWork2);
            t2 = new Thread(tstart);
            t2.IsBackground = true;
            t2.Start();
        }
    }

    private void DoWork1()
    {
        Thread.Sleep(5000);
        this.Label2.Text = "Done in 5 sec!";
        this.UpdatePanel1.Update();
    }

    private void DoWork2()
    {
        Thread.Sleep(10000);
        this.Label1.Text = "Done in 10 sec!";
        this.UpdatePanel2.Update();
    }
}
5个回答

2

只需在每个UpdatePanel中放置一个指向asp:Timer的Trigger标签,并将间隔设置为5000和10000毫秒。

以下是您要求的使用UpdatePanel的解决方案,但要注意,每5秒和10秒都会触发一次Timer的PostBack:

我建议使用javascript或jQuery来避免PostBacks。

ASPX:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
    Inherits="WebApplication1.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server"/>

        5 sec:
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick"/>
            </Triggers>
            <ContentTemplate>
                <asp:Label ID="Label2" runat="server" Text="Label"/><br />
            </ContentTemplate>
        </asp:UpdatePanel>
        <asp:Timer ID="Timer1" runat="server" Interval="5000"
            OnTick="Timer1_Tick"/><br />

        10 sec:
        <asp:UpdatePanel ID="UpdatePanel2" runat="server">
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Timer2" EventName="Tick"/>
            </Triggers>
            <ContentTemplate>
                <asp:Label ID="Label1" runat="server" Text="Label"/><br />
            </ContentTemplate>
        </asp:UpdatePanel>
        <asp:Timer ID="Timer2" runat="server" Interval="10000"
            OnTick="Timer2_Tick"/> 
    </form>
</body>
</html>

C#

using System;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Timer1_Tick(object sender, EventArgs e)
        {
            this.Label2.Text = "Done in 5 sec!";
        }

        protected void Timer2_Tick(object sender, EventArgs e)
        {
            this.Label1.Text = "Done in 10 sec!";
        }
    }
}

0

您的预渲染处理程序中的连接正在阻止渲染返回到客户端。我猜想您可以尝试使用以下方式:

if (t1 != null) {
    t1.join();
} else if (t2 != null) {
    t2.join();
}

那段代码的不幸之处在于它依赖于知道哪个线程会先返回,这是一个副作用。

然而,如果你只是想弄清楚如何从服务器向客户端发送事件(并且html 5是一个选项),我建议你研究一下服务器发送事件(或者如果你需要全双工通信,则使用Web套接字)。如果html 5不是一个选项,我相信你可以使用一些JavaScript技巧来模拟Web套接字。你可以在这里这里阅读一些相关信息。

编辑:添加了非HTML 5替代方案的链接


0

我怀疑你并没有像你想的那样异步调用这个函数,因为有线程的等待。看起来你基本上是在说在线程2终止之前阻塞OnPrerender函数。 因为1和2都是从同一个方法调用的,所以在两者完成之前你会被阻塞。如果你加入一些写行代码来查看什么时候调用了哪些函数,可能会更容易看清楚发生了什么。

我还怀疑根据我所知,在prerender完成之前,1上的文本实际上不会更新。传统的ASP.NET,在prerender完成之后才会向客户端发送任何内容。但是我对UpdatePanel不是很了解,所以对于那个问题可能是胡说八道,并预计会被扣分...


0

相反,您可以使用2个计时器控件,一个间隔为5000,另一个间隔为10000


0

您能使用.NET 4.5吗?还是只能使用早期版本?v4.5有很多新功能,使得创建异步方法变得非常简单,无需担心线程管理。这个链接有一个很好的解释,如何使用新的Task任务和async/await运算符实现异步方法:在ASP.NET 4.5 Web Forms中处理异步操作

基本上,您只需要为每个负责更新updatepanel的方法创建一个Task,并在页面加载时启动它。完成后,每个任务可以休眠5或10秒钟,然后调用自身,以达到您想要的效果。


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