更新另一个线程中的进度条

时间:2017-10-09 09:10:25

标签: c# multithreading progress-bar

我已经阅读了很多关于这个主题的文章和其他问题,但是因为我对C#非常陌生并且总体上使用线程,所以答案很遗憾地主要是为了让我复杂化或者不适用于我的问题。

我有这个进度条,它将填充非常小的步骤,大多数为0.03%。当正常包含它时,它在操作结束时从一个instand中的0-100开始,每次都经过并每次以0.03%的步长更新它。我相信在另一个线程中更新进度条可以解决这个问题,但我很遗憾对此主题一无所知,现在还可以阅读它。

这是我的进度条将会更新的代码部分:

public void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
    string source4count = source.ToString();
    if (checkSubdirCase == 0)
    {
        allfiles = System.IO.Directory.GetFiles(source4count, "*.*", System.IO.SearchOption.AllDirectories);
        allFilesNum = allfiles.Length;
        progressbarinterval = 0;                    
        progressbarinterval = 100 / allFilesNum;
        Progressbarvalue = 0;
    }

    if (Directory.Exists(target.FullName) == false)
    {
        Directory.CreateDirectory(target.FullName);
    }

    foreach (FileInfo fi in source.GetFiles())
    {
        //HERE IS THE UPDATING OF THE PROGRESSBAR
        fi.CopyTo(System.IO.Path.Combine(target.ToString(), fi.Name), true);
        Progressbarvalue = Progressbarvalue + progressbarinterval;                      
        ProgressBarCopy.Value = Progressbarvalue;
    }
    foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
    {
        DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
        checkSubdirCase = 1;
        CopyAll(diSourceSubDir, nextTargetSubDir);
    }
}

我希望有人可以帮助我,并以简单的方式解释如何解决这个问题以及背景工作者的实际工作方式。 此致

3 个答案:

答案 0 :(得分:2)

您可能希望创建一个后台工作程序(这发生在UI线程上),如下所示:

var worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(WorkerDoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(WorkerProgressChanged);

在您的DoWork方法中,您将执行当前在CopyAll方法中执行的所有操作,只会更改进度处理。你需要调用worker.ReportProgress(...),然后它将封送回UI线程并调用你的WorkerProgressChanged方法。在WorkerProgressChanged方法中,您可以更新进度条。

但是,您应该意识到在UI线程和BackgroundWorker线程之间切换相当昂贵,因此您应该仅在实际更改了对UI产生影响的数量时报告进度。

答案 1 :(得分:2)

另一个解决方案是在进度条上使用带有调用的任务

更改按钮上的代码

//CopyAll(); //Old
Task.Run(() => CopyAll());

使用调用的方法

public void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
    string source4count = source.ToString();
    if (checkSubdirCase == 0)
    {
        allfiles = System.IO.Directory.GetFiles(source4count, "*.*", System.IO.SearchOption.AllDirectories);
        allFilesNum = allfiles.Length;
        progressbarinterval = 0;                    
        progressbarinterval = 100 / allFilesNum;
        Progressbarvalue = 0;
    }

    if (Directory.Exists(target.FullName) == false)
    {
        Directory.CreateDirectory(target.FullName);
    }

    foreach (FileInfo fi in source.GetFiles())
    {
        //HERE IS THE UPDATING OF THE PROGRESSBAR
        fi.CopyTo(System.IO.Path.Combine(target.ToString(), fi.Name), true);
        Progressbarvalue = Progressbarvalue + progressbarinterval;                      
        ProgressBarCopy.Invoke(new MethodInvoker(delegate { ProgressBarCopy.Value = Progressbarvalue; }));
    }
    foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
    {
        DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
        checkSubdirCase = 1;
        CopyAll(diSourceSubDir, nextTargetSubDir);
    }
}

答案 2 :(得分:1)

使用Background Worker是一个不错的选择。

var worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
worker.ProgressChanged += new 
ProgressChangedEventHandler(Worker_ProgressChanged);
worker.RunWorkerCompleted += new 
RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);


private void Worker_DoWork(object sender, DoWorkEventArgs e)
{

 ...
  foreach (FileInfo fi in source.GetFiles())
   {
    //Copying the files..

  // Calling the ReportProgress method would fire the worker_ProgressChanged event
    worker.ReportProgress(0, progressState)
} 


  }

  private void worker_ProgressChanged(object sender, 
                                      ProgressChangedEventArgs e)
   { 
        // This is where you would have the UI related changes. 
       //In your case updating the progressbar. 
      // While the files are being copied this would update the UI.
  }

 private void Worker_RunWorkerCompleted(object sender, 
 RunWorkerCompletedEventArgs e)
 {
 worker.CancelAsync();

 }