简体   繁体   English

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

[英]Update progress bar in another thread

I've read so many articles and other questions about this topic but because i am very new to C# and working with threads in general the answers were sadly mostly to complicated for me and or not applicable for my problem. 我已经阅读了很多有关该主题的文章和其他问题,但是由于我对C#还是很陌生,并且通常使用线程,因此答案对我来说大部分都是复杂的,或者不适用于我的问题。

I have this progressbar which will be filled with very small steps mostly 0.03%. 我有这个进度条,其中将包含非常小的步骤,大部分为0.03%。 When including this normally it went from 0-100 in an instand at the very end of the operation altough i runs through every time and updates it in 0.03% steps every time. 当正常情况下包括它时,它在操作结束时从0到100逐渐变小,尽管我每次都运行并每次以0.03%的步长更新它。 I believe updating the progress bar in another thread will do the trick, but i sadly have no understanding of this topic as of now altough reading into it. 我相信在另一个线程中更新进度条可以解决问题,但是令人遗憾的是,到目前为止我对这个主题还没有足够的了解。

This is the code section where my progress bar will be updated: 这是我的进度栏将更新的代码部分:

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);
    }
}

I hope someeone can help me and explain in a simple way how to tackle this and how background workers actually work. 我希望有人能帮助我,并以简单的方式说明如何解决此问题以及后台工作者的实际工作方式。 Regards 问候

You will probably want to create a background worker (this happens on the UI thread) like this: 您可能想要创建一个背景工作程序(这在UI线程上发生),如下所示:

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

In your DoWork-method, you will do everything that you currently do in the CopyAll-method, only the progress handling will change. 在您的DoWork方法中,您将执行当前在CopyAll方法中所做的所有事情,只有进度处理会改变。 You need to call worker.ReportProgress(...), this will then marshal back to the UI thread and invoke your WorkerProgressChanged-method. 您需要调用worker.ReportProgress(...),然后将其编组回UI线程并调用您的WorkerProgressChanged方法。 In the WorkerProgressChanged-method, you can update your progress bar. 在WorkerProgressChanged方法中,您可以更新进度栏。

However, you should be aware of the fact that switching between the UI thread and your BackgroundWorker thread is rather expensive, so you should only report progress when it has really changed by an amount that has an effect on the UI. 但是,您应该意识到以下事实:在UI线程和BackgroundWorker线程之间进行切换非常昂贵,因此,仅应在进度实际发生变化而对UI产生影响的情况下才报告进度。

A other solution is the use of an task with a invoke on the progressbar 另一种解决方案是将任务与进度条上的调用一起使用

Change the code on your Button 更改按钮上的代码

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

Your method with a invoke 您的方法与调用

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);
    }
}

Using the Background Worker is a good option. 使用后台工作程序是一个不错的选择。

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();

 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM