ASP.Net:异步更新面板加载两个更新面板

发布于 2024-08-13 16:53:48 字数 3461 浏览 2 评论 0原文

我正在尝试在网站上的更新面板中异步显示数据,其中数据检索任务需要不同的时间。我想更新每个面板以在每个任务完成后在页面上显示数据。

但是,无论我尝试什么,所有更新面板都会在最后一个任务完成后更改其内容。

例如:

我有两个任务:

  • 一个任务在 5 秒后尝试更新 UpdatePanel1 中的标签
  • 一个在 10 秒后尝试更新 UpdatePanel2 中的标签

预期结果是仅 UpdatePanel1 中的标签在 5 秒后更改,但是,两个更新面板在 10 秒后同时更新。

两个更新面板都设置为 updatemode="Conditional",并被告知从客户端 javascript 回发。下面是上面示例的完整列表。

我在这里缺少什么?如何加载一个更新面板,然后加载另一个更新面板,使这两个任务异步运行?

谢谢,

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();
    }
}

I am trying to asynchronously display data in update panels on a website where the data retrieval tasks take different times. I would like to update each panel to show the data on the page after each task finishes.

However, no matter what I try, all Update Panels change their content after the last task has completed.

For example:

I have two tasks:

  • One that tries to update a label in UpdatePanel1 after 5 seconds
  • One that tries to update a label in UpdatePanel2 after 10 seconds

The expected result is to have only the label in UpdatePanel1 change after 5 seconds, however, both update panels update at the same time, at 10 seconds.

Both update panels are set to updatemode="Conditional" and they are told to postback from client javascript. Below is a complete listing of the example above.

What am I missing here? How do I get one update panel to load, and then the other, having both tasks run asynchronously?

Thanks,

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吹泡泡o 2024-08-20 16:53:48

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

下面是您使用 UpdatePanel 提出的解决方案,但要小心,因为每隔 5 秒和 10 秒就会为计时器触发一次 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!";
        }
    }
}

Just put a Trigger tag inside each UpdatePanel pointing to a asp:Timer and set interval to 5000 and 10000 miliseconds.

Below is the solution that you ask, using UpdatePanel, but take care because each 5 and 10 seconds there is a PostBack fired for Timer:

I recommend using of javascript or jQuery to avoid 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!";
        }
    }
}
懷念過去 2024-08-20 16:53:48

我怀疑您没有像您认为的线程连接那样异步调用它。看起来您基本上是在说阻止 OnPrerender 直到线程 2 终止。
因为 1 和 2 都是从同一个方法调用的,所以在两者都完成之前您会被阻塞。如果您添加一些写入行来查看调用的时间,可能会更容易看到正在发生的事情。

据我所知,我还怀疑 1 上的文本在预渲染完成之前不会真正更新。传统的 ASP.NET,在预渲染完成之前,不会将任何内容发送回客户端。但我对更新面板不太了解,所以我可能会在那个面板上谈论垃圾,并预计会被降价......

I suspect that you aren't calling this as asynchronously as you think b/c of the thread joins. It looks like you're basically saying block OnPrerender until thread 2 terminates.
Because both 1 and 2 are being called from the same method, you're blocked until both are done. If you throw in some writelines to see when things are being called, it might become a little easier to see what is happening.

I also suspect the text on 1 won't really update until prerender is complete from what I know. Traditional ASP.NET, nothing is sent back to the client until after prerender completes. But I don't know much about update panel, so I could be talking junk on that one and anticipating being marked down...

夏日浅笑〃 2024-08-20 16:53:48

预渲染处理程序中的连接会阻止渲染返回客户端。我怀疑你可以做这样的事情,而不是你所拥有的:

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

不过,该代码有一个不幸的副作用,即依赖于知道哪个线程将首先返回。

但是,如果您只是想弄清楚如何将事件从服务器发送到客户端(并且 html 5 是一个选项),我建议您查看 服务器发送的事件(如果需要全双工通信,则为 Web 套接字)。如果 html 5 不是一个选项,我相信您可以使用一些 javascript hack 来模拟 Web 套接字。您可以在此处此处

编辑:添加了非 html 5 替代品的链接

The joins in your pre-render handler are blocking the rendering from coming back to the client. Instead of what you have, I suspect that you could do something like this instead:

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

That code has the unfortunate side-effect of being dependent on knowing which thread will return first, though.

However, if you're just trying to figure out how to send events from the server to client (and html 5 is an option), I'd recommend looking into server-sent events (or web sockets if you require full duplex communication). If html 5 isn't an option, I believe you can use some javascript hacks to simulate web sockets. You can read about some of those here and here.

edit: added links for non-html 5 alternatives

私藏温柔 2024-08-20 16:53:48

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

Instead you can use 2 timer controls, one with interval of 5000 and another with interval of 10000

辞别 2024-08-20 16:53:48

您可以使用 .NET 4.5 还是只能使用早期版本? v4.5 具有许多新功能,使创建异步方法变得非常简单,而不必担心线程管理。此链接很好地解释了如何使用新的 任务 任务和 异步/等待 运算符:在 ASP.NET 4.5 Web 表单中使用异步操作

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

Are you able to use .NET 4.5 or are you restricted to earlier versions? v4.5 has alot of new features that make creating asynchronous methods pretty straight forward without having to worry about thread management. This link has a good explanation of how to implement an asynchronous method with the new Task task and async/await operators: Working with Asynchronous Operations in ASP.NET 4.5 Web Forms

Essentially you'd just have to create a Task for each method responsible for updating the updatepanel and fire it up on page load. At completion each task could sleep for 5 or 10seconds before calling itself to give you the effect you're after.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文