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

本文关键字:结束 BackgroundWorker ProgressChanged 函数 | 更新日期: 2023-09-27 18:17:35

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

我试了所有可能的组合,我读了所有我能读的,但我不能解决这个问题。

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)触发。

有人能解释一下为什么,帮我解决吗?

谢谢!

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

当前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类的示例了解更多详细信息:如何:实现使用后台操作的表单,MSDN.