Backgroundworker总是忙碌的

5
我对事件处理程序和后台工作者的使用很陌生,因此我可能会错过一些非常明显的东西。尽管如此,我已经试图解决这个问题两天了,所以我想看看有人能否提供帮助。
我有一个名为SqlExpressDownloader的后台工作者。它在我的程序开始运行时启动,余下的工作运行完毕后,它应该等待SqlExpressDownloader_DoWork()方法中的操作完成后才继续进行。唯一的问题是,由于某种原因,每当我执行while(SqlExpressDownloader.IsBusy)时,它总是响应繁忙,因此将永远等待。
以下是事件处理程序的代码:
    private void SqlExpressDownloader_DoWork(object sender, DoWorkEventArgs e)
    {
        string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
        Debug.WriteLine(sSource);
        Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
        if (!System.IO.File.Exists(sSource))
        {
            WebClient oWebClient = new WebClient();
            oWebClient.DownloadProgressChanged += DownloadProgressChanged;
            oWebClient.DownloadDataCompleted += DownloadComplete;

            oWebClient.DownloadFileAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);

            while (oWebClient.IsBusy)
            {
                Thread.Sleep(100);
            }

            e.Result = "";
            DownloadFinished = true;
        }
    }

我已经查看了代码并观察了它完成这个方法。我甚至在DownloadFinished = true之后添加了一个return,但它仍然响应繁忙。我想知道如何使后台工作者不繁忙。

编辑 事件都在构造函数中添加,如下所示:

        SqlExpressDownloader = new BackgroundWorker();
        SqlExpressDownloader.DoWork += new DoWorkEventHandler(this.SqlExpressDownloader_DoWork);
        SqlExpressDownloader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.SqlExpressDownloader_RunWorkerCompleted);
< p > RunWorkerCompleteEventHandler 的格式如下:

    private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            Debug.WriteLine("The actions are complete.");
        }
        else
        {
            Debug.WriteLine("Error in completed work.");
        }
    }

但是,当我上次进行调试时,它实际上并没有触发。


你是如何启动工作进程的? - Patrick
你在检查 worker 的 IsBusy 时是否使用了类似于方法体中的 while 循环?当方法完成时,RunWorkerCompleted 事件是否会触发? - Patrick
while循环看起来几乎与此处列出的一样。我在问题中更新了有关RunWorkerCompleted的信息。 - ijb109
还有其他代码添加了一个处理程序到DoWork事件吗?也许在.designer.cs文件中?你的代码应该按照你编写的方式工作。 - Patrick
这个问题在这里已经得到了解答:https://dev59.com/pmYq5IYBdhLWcg3wfwxx?rq=1问题在于完成事件是在主线程中运行的 - 你不能只是坐在那里等待isBusy变为false。 - Arunas
显示剩余2条评论
3个回答

3

不要使用循环查询 SqlExpressDownloader.IsBusy,尝试订阅BackgroundWorkerRunWorkerCompleted事件,并将应该在DoWork事件完成后才发生的代码放在那里。

您还可以访问RunWorkerCompletedEventArgs,以确保没有从BackgroundWorkerDoWork部分抛出错误。

    ...
    ...
    SqlExpressDownloader.RunWorkerCompleted += SqlExpressDownloader_RunWorkerCompleted;
    SqlExpressDownloader.RunWorkerAsync();
}

private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // do something in response to the error
    }

    // stuff to do after DoWork has completed
}

我在学习如何使用这些技术时,发现Joe Albahari的教程非常有帮助。

1

我遇到了类似的问题。DownloadASync 会被触发,但 .IsBusy 总是保持为 true。

这可能不是一个常见的问题,只是想分享一下我的解决方法。

我使用了

MessageBox.Show(new Form() { TopMost = true }, "", "")

这是原因。我还尝试了以下内容:
var t = new Form() { TopMost = true };
MessageBox.Show(t, "", "");
t.Dispose();

这导致了相同的问题。
我的代码有多个线程,我想其中一个可能被卡住了,或者可能是MessageBox(new Form() { TopMost = true; })调用创建了一个卡住的线程。
一旦我删除了那部分,例如:
MessageBox.Show("", "");

一切又像预期的那样正常工作了。

所以可能是你在其他地方创建了另一个线程,导致出现了问题。


1

你可以使用更加优雅的async/await解决方案替换你的代码,例如:

private async Task SqlExpressDownloadAsync()
{
    string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
    Debug.WriteLine(sSource);
    Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
    if (!System.IO.File.Exists(sSource))
    {
        WebClient oWebClient = new WebClient();
        oWebClient.DownloadProgressChanged += DownloadProgressChanged;
        oWebClient.DownloadDataCompleted += DownloadComplete;
        await oWebClient.DownloadFileTaskAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);  
    }   
}

我对任务不太熟悉。我能像在BackgroundWorker上使用事件处理程序一样跟踪下载的进度吗?我的项目涉及GUI组件。我会尝试这个。 - ijb109
@Patrick 你能详细说明一下吗?这段代码正在等待 DownloadFileTaskAsync 函数的执行。 - Alex S
如果File.Exist检查UNC路径下的文件,可能需要几秒钟。您运行异步操作的限制是什么?它是不超过8行代码的通用限制,您认为这不应该花费“太长”的时间吗? - Patrick
如果 Paths.Settings_Common 是一个从数据库加载某些内容的属性,那么这也可能需要一些时间。实际情况是你不知道需要多长时间,因为无法确定事物是如何实现的。 - Patrick
@Patrick,你说得对,我要么将整个代码移动到Task.Run中,要么如果这里真的不需要检查文件是否存在,就删除文件存在性检查。我认为检查文件是否存在并不是判断先前下载的完全相同版本文件的好方法。 - Alex S
显示剩余4条评论

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