使用!Task.IsCompleted显示用户当前GUI的进度

时间:2011-11-23 15:48:36

标签: c# .net .net-4.0 task-parallel-library

我的任务可能需要一段时间才能完成。

我尝试了一个简单的演示,但由于某些原因它锁定了GUI线程。我认为任务是异步的,GUI会在任务运行时更新。

这可以通过任务吗?

    private void button5_Click(object sender, EventArgs e)
    {
        var task = Task.Factory.StartNew(() => DoSomething());
        while (!task.IsCompleted)
        {
            label1.Text += ".";
            if (label1.Text.Length == 5)
                label1.Text = ".";
        }
    }

    private void DoSomething()
    {
        Thread.Sleep(5000);
    }

更新:在Damien的回答之后我尝试了以下但是CPU增加了

        private void button5_Click(object sender, EventArgs e)
        {
            var task = Task.Factory.StartNew(() => DoSomething());
        }
        public delegate void dgUpdateLabel();

        private void UpdateLabel()
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new dgUpdateLabel(UpdateLabel), new object[] { });
            }
            else
            {
                label1.Text += ".";
                if (label1.Text.Length == 5)
                    label1.Text = ".";
            }
        }

        private void DoSomething()
        {
            var task = Task.Factory.StartNew(() => Sleep());
            while (!task.IsCompleted)
            {
                UpdateLabel();
            }
        }

        private void Sleep()
        {
            Thread.Sleep(5000);
        }

UPDATE2:我认为尝试更新标签的速度太快,无法处理。如果在UpdateLabel方法调用之后放置一个Thread.Sleep(500),它将按预期工作。

3 个答案:

答案 0 :(得分:1)

您需要在UI更新之前从button_Click处理程序返回。也许看看运行计时器,以执行定期更新。

目前,您的UI线程正在紧挨着while (!task.IsCompleted)运行,可能会耗尽所有CPU。


要使用计时器,您必须在更高级别(例如私有字段)而不是本地变量中公开task变量。

答案 1 :(得分:0)

根据我们的聊天更新:):

private void Form1_Load(object sender, EventArgs e)
{
  CancellationTokenSource cts = new CancellationTokenSource();
  Task worker = new Task(() => DoSomething());
  Task ui_updater = new Task(() => UpdateGui(CancellationToken token));
  worker.Start();
  updater.Start();
  // Worker task completed, cancel GUI updater.
  worker.ContinueWith(task => cts.Cancel());
}
private void DoSomething()
{
 // Do an awful lot of work here.
}
private void UpdateGui(CancellationToken token)
{ 
  while (!token.IsCancellationRequested)
 {      
   UpdateLabel();
   Thread.Sleep(500);
 }
}
private void UpdateLabel()
{
  if (this.InvokeRequired)
  {
   this.BeginInvoke(new Action(() => UpdateLabel()), new object[] { });
  }
    else
    {
        label1.Text += ".";
        if (label1.Text.Length >= 5)
            label1.Text = ".";
    }
}

答案 2 :(得分:0)

我调整了Alex's code,IMO有多个错误(并且无法运行):

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinForm
{
  public partial class Form1 : Form
  {
    readonly CancellationTokenSource _cts = new CancellationTokenSource();
    public Form1()
    {
      InitializeComponent();
    }
    private void button5_Click(object sender, EventArgs e)
    {
      var task = Task.Factory.StartNew(() => DoSomething());
      Task updatingLabel = Task.Factory.StartNew(() => UpdateLabelValidated(_cts));
      task.ContinueWith(_=> _cts.Cancel());
    }
    private void DoSomething()
    {
      Thread.Sleep(20000);
    }
    private void UpdateLabelValidated(CancellationTokenSource token)
    {
      while (!token.IsCancellationRequested)
      {
        UpdateLabel();
        Thread.Sleep(500);
      }
    }
    private void UpdateLabel()
    {
      if (this.InvokeRequired)
      {
        this.BeginInvoke(new Action(UpdateLabel), new object[] { });
      }
      else
      {
        label1.Text += ".";
        if (label1.Text.Length > 5)
          label1.Text = ".";
      }
    }
  }
}