Используйте! Task.IsCompleted, чтобы показать текущий прогресс пользователя в GUI - PullRequest
0 голосов
/ 23 ноября 2011

У меня есть задача, выполнение которой может занять некоторое время.

Я попробовал простую демонстрацию, но она по какой-то причине блокирует поток графического интерфейса. Я думал, что задача будет асинхронной, и графический интерфейс будет обновляться во время выполнения задачи.

Возможно ли это с помощью задания?

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

ОБНОВЛЕНИЕ: После ответа Дэмиена я попробовал следующее, но ЦП увеличил

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

ОБНОВЛЕНИЕ2: Я думаю, что скорость попытки обновить ярлык слишком высока для него. Если вы поместите Thread.Sleep (500) после вызова метода UpdateLabel, он будет работать как положено.

Ответы [ 3 ]

1 голос
/ 23 ноября 2011

Вам нужно вернуться из обработчика button_Click, прежде чем пользовательский интерфейс обновится. Возможно, посмотрите вместо этого на запуск таймера, чтобы выполнять периодические обновления.

В данный момент ваш поток пользовательского интерфейса работает с такой жесткой while (!task.IsCompleted) и, вероятно, использует весь ваш процессор, делая это.


Чтобы использовать таймер, вы должны предоставить свою переменную task на более высоком уровне (например, в качестве частного поля), а не локальную переменную.

0 голосов
/ 12 марта 2013

Я настроил Код Алекса , в котором 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 = ".";
      }
    }
  }
}
0 голосов
/ 23 ноября 2011

Обновление по нашему чату :):

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 = ".";
    }
}
...