简单的BackgroundWorker不会更新网页上的标签

时间:2014-04-29 12:31:34

标签: c# asp.net multithreading backgroundworker

我使用了一段有用的简单代码 post

它使用按钮和标签,标签应报告“已完成10%”......“已完成20%”......依此类推。

当我调试时,代码被点击,但我的标签没有在浏览器上更新。

我试过&没有更新面板,有和没有母版页。

protected void btnStartThread_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }
        });



        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });


        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();

4 个答案:

答案 0 :(得分:5)

您可能会进行长时间轮询以获取更新后的结果。我个人不会在Web应用程序中使用后台工作程序。另外,请考虑查看SignalR,服务器发送事件和异步和等待或任务并行库。

答案 1 :(得分:4)

BackgroundWorker不适合ASP.NET,并且不能很好地与ASP.NET一起使用,因为ASP.NET适用于请求/响应模型。要接收任何更新,客户端的浏览器需要从服务器请求信息。例如,要更新Label,您需要向服务器发送新值请求。

一个选项可能是在客户端上使用AJAX来更新页面。但是,不是使用正式的AJAX,而是使用iframe,这是一种异步执行长时间运行过程的好方法,而不依赖于任何特定的AJAX框架。单击该按钮时,会动态生成一个不可见的iframe并用于在后台执行LongRunningProcess.aspx

<head runat="server">
<script type="text/javascript">
    function BeginProcess() {
        var iframe = document.createElement("iframe");
        iframe.src = "LongRunningProcess.aspx";
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        document.getElementById('trigger').disabled = true;
    }

    function UpdateProgress(PercentComplete, Message) {
        document.getElementById('<%= Label1.ClientID %>').innerHTML = PercentComplete + '% ' + Message;
}
</script>
</head>

<body>
   <form id="form1" runat="server">
   <div>
    <input type="submit" value="Start Long Running Process" id="trigger" 
       onclick="BeginProcess(); return false;" style="width: 185px;"/>
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
   </div>
   </form>
</body>

LongRunningProcess.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
   for (int i = 1; i <= 9; i++)
   {
       UpdateProgress(i * 10, " Completed.");
       System.Threading.Thread.Sleep(1000);
   }
   UpdateProgress(100, "Finished!");
}

protected void UpdateProgress(int PercentComplete, string Message)
{
    Response.Write(String.Format("<script type=\"text/javascript\">parent.UpdateProgress({0}, '{1}');</script>", PercentComplete, Message));
    Response.Flush();
}

您可以在Dave Ward的精彩文章中看到结果并阅读更多内容:  Easy incremental status updates for long requests.

答案 2 :(得分:3)

很少见,但.NET有时可以同步运行异步任务(从MSDN上的文档中可能会发生这种情况并不清楚)但是如果这种情况发生在你的情况下它将阻止你的WinForms应用程序中的消息循环。

要测试此理论,您可以尝试在ProgressChanged处理程序和DoWork处理程序中调用Application.DoEvents(),看看是否有帮助。这是一个丑陋的工作,但如果disptacher同步运行您的任务,它应该强制UI更新。

答案 3 :(得分:2)

您基本上有两种选择。

首先,您可以使用JavaScript在浏览器上通过计时器轮询以获得当前完成百分比。 setInterval是显而易见的使用方法,您可以使用jQuery或类似方法对服务器执行AJAX调用。但这有点低效,因为你的服务器听起来好像知道它何时取得进展或完成,所以服务器应该提出事件。

两个,你想要的更多,就是使用SignalR。你已经把事情设置为&#34;推送&#34;从服务器引发定时事件,但在HTTP中没有简单的方法(HTML5 WebSockets也是另一种选择)。使用像SignalR这样的服务器推送技术可以让你创建&#34; hubs&#34;向客户举办活动。它们可以是特定于用户的目标事件或所有客户类型的事件 - 由您决定。

在这里查看介绍/演示。他们很容易解决相当困难的问题:http://www.asp.net/signalr

另外,正如其他人所说,您可能不想使用BackgroundWorker。尝试QueueBackgroundWorkItem。 http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx