2015-10-13 100 views
0

我有我的类中有一些内部循环的方法。 这个方法的主要目的是转换一些文件,所以我在我的表单中放置了一个进度条,在每个文件转换后应该更新。C#BackgroundWorker ProgressChanged不会被触发,直到函数结束

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

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

根据您发布的代码,我认为您对BackgroundWorker存在误解。该工作应该发生在BackgroundWorker内部(即将逻辑从Convert转换为bw_DoWork)。在循环的每次迭代(在DoWork!内部)触发ReportProgress方法。 – syazdani

+0

你能否详细说明一下?因为我试图运行DoWork中的代码,但是如何在循环之后触发ReportProgress方法?我在哪里放RunWorkerAsync? –

+1

有很多事情,你需要改变,以使其工作。您应该在bw_DoWork中运行Convert方法,但不应该访问内部控件(如chk,convertedVideosL),也不应该使用MessageBox-es。你应该从那里调用bw.ReportProgress并在bw_ProgressChanged中处理它,你可以在这里更新你的UI。坦率地说,使用'async/await'完成所有这些工作会容易得多,你有这个选择吗? –

回答

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

+0

现在它变得令人困惑:)这是我第一次尝试实现背景工作,因为我想学习这个功能,但是我不能跟着你的代码(当然我的错误),TWorkerResult和TWorkerArgument.Could你可以让它成为一个比较简单? –

+1

@Daniel,'TWorkerArgument'是你想要发送给'BackgroundWorker'的数据类型,'TWorkerResult'是你想要返回的数据类型。谢尔盖不能告诉你他们应该是什么,因为你没有告诉我们你的数据是什么,也没有告诉我们你的数据。 –

+0

@DourHighArch,对!究竟! –