【问题标题】:GUI freezes when text and progressbar changes文本和进度条更改时 GUI 冻结
【发布时间】:2014-01-27 22:29:20
【问题描述】:

我正在创建一个使用 TextBox 和 ProgressBar 的程序,每次 TextBox 中的文本更改或 ProgressBar 执行一个步骤时,GUI 都会冻结,在操作完成之前我无法执行任何操作。

我知道我需要在不同的线程上运行它们,但我搜索了整个网络并没有找到适合我的方法。

这是一个例子,当我写一个文件,我需要得到它的进度:

for (int l = 0; l < newfile.Length; l++)
{
  vfswriter.Write(newfile[l]);
  double percentage = ((double)l / (double)newfile.Length * 100);
  this.progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}

这是我更改文本时的示例:

this.richTextBox1.Text = "Installing patch : ";

任何帮助将不胜感激。

【问题讨论】:

  • 我没有看到使用 BackgroundWorker 的尝试。这可能会有所帮助。
  • 我试过了,但我的代码是这样的:我调用了一个方法,并且在该方法中它使用了文本和 backgroundworker
  • 附带说明 - 您可能会丢失 percentage 变量并将进度条更新编码为 this.progressBar1.Value = l * 100 / newfile.Length;。整数数学可以满足您的需求。

标签: c# winforms progress-bar backgroundworker


【解决方案1】:

使用BackgroundWorker,将你的for循环放在DoWork方法中:

backgroundWorker1.DoWork += doWork;

private void doWork(object sender, DoWorkEventArgs e)
{
    for (int l = 0; l < newfile.Length; l++)
    {
       vfswriter.Write(newfile[l]);
       double percentage = ((double)l / (double)newfile.Length * 100);
       this.progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
    }
}

当你想执行你的循环调用backgroundWorker1.RunWorkerAsync()方法时。

您也可以使用ProgressChanged 事件来更新您的进度条:

backgroundWorker1.DoWork += doWork;
backgroundWorker1.ProgressChanged += progressChanged;

private void doWork(object sender, DoWorkEventArgs e)
{
    for (int l = 0; l < newfile.Length; l++)
    {
       vfswriter.Write(newfile[l]);
       double percentage = ((double)l / (double)newfile.Length * 100);
       var value = int.Parse(Math.Truncate(percentage).ToString());
       backgroundWorker1.ReportProgress(value);
    }
}

private void progressChanged(object sender, ProgressChangedEventArgs e)
{
    this.progressBar1.Value = e.ProgressPercentage;
}

更新:如果您想将参数传递给 DoWork 方法,您可以在调用 backgroundWorker1.RunWorkerAsync() 方法时这样做:

backgroundWorker1.RunWorkerAsync(argument);

您可以使用e.ArgumentDoWork 方法中访问它。如果您想传递多个参数,您可以使用Anonymous Types 来解决问题。例如:

var myArguments = new { Property1 = "some value", Property2 = myId, Property3 = myList };
backgroundWorker1.RunWorkerAsync(myArguments);

在DoWork方法中:

dynamic arguments = e.Argument;
var arg1 = arguments.Property1;
var arg2 = arguments.Property2;
// and so on...

【讨论】:

  • 您没有使用 ReportProgress。您正在从后台线程更新 GUI。
  • @LarsTech 现在我已经添加了 :-)
  • 如何将参数传递给 DoWork ?
  • @Meydan 当您调用 backgroundWorker1.RunWorkerAsync() 时,您可以传递您的论点:backgroundWorker1.RunWorkerAsync(parameter);,在 DoWork 方法中您可以通过以下方式访问它:e.Argument
  • 如果我需要 2 个参数怎么办?因为在代码中有 vfswriter 和 newfile
【解决方案2】:

您可以使用 Task 类来创建和运行后台线程。一个警告!任何时候你想从一个不是主线程的线程更新一些东西,你必须使用 Dispatcher 在主线程上运行代码。

我的示例代码:

System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(() =>
{
 for (int l = 0; l < newfile.Length; l++)
 {
   vfswriter.Write(newfile[l]);
   double percentage = ((double)l / (double)newfile.Length * 100);
   //This runs the code inside it on the main thread (required for any GUI actions
   App.Current.Dispatcher.Invoke((Action) (() =>
   {
     this.progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
   }
 }
});
task.Start();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2016-01-02
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多