【问题标题】:Enabling responsive GUI while processing在处理时启用响应式 GUI
【发布时间】:2016-06-08 10:17:45
【问题描述】:

当我点击一个按钮时,我的 winform 中有一个冗长的处理;即,我正在加载大量文件并处理它们。在处理期间,我的 GUI 冻结且无响应,这是一个问题,因为处理可能需要 10 分钟以上。有没有办法将代码放入某种气泡或其他东西中,以便我可以在处理文件时使用 GUI?甚至可以添加“取消”按钮。

编辑:René 的解决方案有效,这也是我想要的progressbar 控件:

private async void button1_Click(object sender, EventArgs e)
   {  
       progressBar1.Maximum = ValueWithTOtalNumberOfIterations.Length;
       IProgress<int> progress = new Progress<int>(value => { progressBar1.Value = value;});

       await Task.Run(() =>
       {
           var tempCount = 0;

       //long processing here
       //after each iteration:

           if (progress != null)
           {
               progress.Report((tempCount));
           }
           tempCount++;        
        }            
   }

【问题讨论】:

标签: c# winforms async-await


【解决方案1】:

您可以简单地将按钮的点击处理程序设为async 并启动Task 以进行长时间运行:

public async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false; // disable button to not get called twice

    await Task.Run(() =>
    {
        // process your files
    }

    button1.Enabled = true; // re-enable button
}

编译器把它变成一个状态机。控制流在await 关键字处返回给调用者(UI)。当您的Task 完成后,此方法的执行将恢复。


要使用“取消”按钮,您可以使用TaskCancellationSource 或简单地定义一个标志,您在处理文件时检查该标志,如果设置了该标志,则返回(通过“取消”的点击处理程序) " 按钮):

private bool _stop = false;

private void cancelButton_Click(object sender, EventArgs e)
{
    _stop = true;
}
private async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false; // disable button to not get called twice

    _stop = false;

    await Task.Run(() =>
    {
        // process your files
        foreach(var file in files)
        { 
            if (_stop) return;
            // process file
        }
    }

    button1.Enabled = true; // re-enable button
}

【讨论】:

  • 这太好了,谢谢!但是我现在在处理代码中遇到了一个错误,比如我的DialogResult result = folder.ShowDialog(); 上的 ThreadStateException。表示当前线程必须设置为 STA 模式才能进行 OLE 调用。我知道我不应该在这里问这个问题,但你知道如何解决吗?
  • 哦,您不应该在任务中打开另一个对话框,因为它是在与 ui 不同的线程上执行的。
  • 啊,我明白了。开始处理的按钮首先打开 folderBrowserDialog 以选择文件。然后我应该将 Task.Run 放在它下面吗?
  • 是的,将Task.Run 放在所有与 GUI 相关的操作下方就可以了。然而,由于类似的原因,新的错误也会弹出,因为我在按钮下方有一个textbox,该按钮在处理每个单独的文件后显示一条确认消息。我应该在Task.Run 期间不使用任何与 GUI 相关的操作,还是在这种情况下仍然可以使用 textbox`?
  • 您可以使用BeginInvoke() 或使用IProgress&lt;string&gt; 将进度报告回ui 线程。 SO上有很多关于如何从不同的线程更新winforms ui。
猜你喜欢
  • 1970-01-01
  • 2013-03-19
  • 1970-01-01
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-19
  • 1970-01-01
相关资源
最近更新 更多