C#BackgroundWorker ProgressChanged在函数结束前不会被触发

时间:2015-10-13 18:56:23

标签: c# asynchronous backgroundworker

我的类中有一个方法,里面有一些循环。 这个方法的主要目的是转换一些文件,所以我在表单中放了一个进度条,在每个文件转换后都应该更新。

我尝试了所有可能的组合,并且我阅读了所有可能的内容,但我无法解决这个问题。

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    converterProgressBar.Value = e.ProgressPercentage;
}
只有在我的方法的主循环执行完毕后才会调用

这是我的方法:

public string Convert()
{
    convertBtn.Enabled = false;
    bw.WorkerReportsProgress = true;
    bw.WorkerSupportsCancellation = true;

    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    totalCount = files.length;
    bw.RunWorkerAsync();

    if (!Directory.Exists(folder))
    {
        Directory.CreateDirectory(folder);
    }
    foreach (string file in files)
    {
        countFile++;
        if (chk.Checked)
        {
            class1.DoJob();
        }

        using (// some code))
        {
            using (//some other code))
            {
                try
                {
                    using (// again some code)
                    {
                        // job executing
                    }
                }
                catch (exception
                {

                }   
            }
        }
        convertedVideosL.Text = txtToUpdate;
        convertedVideosL.Refresh();
    }
    countFile = countFile + 1;
    MessageBox.Show("Done");
    countFile = -1;
    return outputFile;
}

以下是BackgroundWorker事件处理程序:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i <= totalCount; i++)
    {
        if (bw.CancellationPending)
        {
            e.Cancel = true;
        }
        else
        {
            int progress = Convert.ToInt32(i * 100 / totalCount);
            (sender as BackgroundWorker).ReportProgress(progress, i);
        }
    }
}

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    converterProgressBar.Value = e.ProgressPercentage;
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled == false)
    {
        convertedVideosL.Text = "Finished!";
    }
    else
    {
        convertedVideosL.Text = "Operation has been cancelled!";
    }
}

但我无法更新每个转换文件的进度条。 它等待foreach循环结束,然后调用bw_ProgressChanged

如果我将RunWorkerAsync()放在foreach循环中,则会抛出一个异常,表示BackgroundWorker正忙,无法执行其他任务。

在我看来DoWork()只执行for循环,然后它不应该知道转换正在进行,但ProgressChanged应该ReportProgress(progress,i)触发。

可以请别人解释我为什么并帮助我解决方案吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

目前,转换不是由BackgroundWorker类型的实例执行的。应该从DoWork事件处理程序调用转换。

请考虑提取与转换相关的功能:

if (!Directory.Exists(folder))
{
    Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
    // Details...
}

进入单独的方法。之后,只需从DoWork事件处理程序调用该方法。

伪代码来证明这个想法:

public void StartConversion()
{
    ...
    TWorkerArgument workerArgument = ...;
    worker.RunWorkerAsync(workerArgument);
    // No message box here because of asynchronous execution (please see below).
}

private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{   
    // Get the BackgroundWorker that raised this event.
    BackgroundWorker worker = sender as BackgroundWorker;
    e.Result = Convert(worker, (TWorkerArgument)e.Argument);
}

private static TWorkerResult Convert(BackgroundWorker worker, TWorkerArgument workerArgument)
{
    if (!Directory.Exists(folder))
    {
        Directory.CreateDirectory(folder);
    }

    foreach (string file in files)
    {
        // Details...
        worker.ReportProgress(percentComplete);
    }

    return ...;
}

private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Show the message box here if required.
}

请相应地替换TWorkerArgumentTWorkerResult类型。

此外,请参阅使用BackgroundWorker类的示例了解其他详细信息:How to: Implement a Form That Uses a Background Operation, MSDN