графический интерфейс Windows зависает при вызове потока из цикла while. Как сделать Gui отзывчивым? - PullRequest
0 голосов
/ 21 сентября 2011
class ...
{
   onClick()
   {
      while(true)
      {
        //call the thread from here
        threadpool(request)//send request to thread using thread pool
      }
   }

   //the function for thread
   threadfunction()//function that thread calls
   {

   // I am not able to change the textbox/datagridview in windowsform from here the main ui gets stuck // 

   }
}

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

Ответы [ 6 ]

3 голосов
/ 21 сентября 2011

while (true) должен быть внутри функции потока, а не в onClick.В противном случае графический интерфейс застревает, потому что он бесконечно выполняет while(true).

2 голосов
/ 21 сентября 2011

Во-первых, не создавайте бесконечный цикл в обратном вызове, поскольку поток пользовательского интерфейса будет выполнять этот цикл навсегда. Затем, если threadfunction() требует обновления пользовательского интерфейса, необходимо повторно синхронизировать код с потоком пользовательского интерфейса:

threadfunction()
{
 myControl.Update(result);
}

class TheControl
{
 public void Update(object result)
 {
  if (this.InvokeRequired)
   this.Invoke(new Action<object>(Update), result);
  else
  {
   // actual implementation
  }
 }
}
2 голосов
/ 21 сентября 2011

Согласно заданному коду while(true) работает вечно. Если у вас есть трудоемкий процесс, вам придется использовать отдельный поток для обработки этого. Если вы выполняете этот трудоемкий процесс в основном потоке (потоке пользовательского интерфейса), он будет занят и не будет учитывать запросы на изменение пользовательского интерфейса, пока не выполнит эту задачу. Вот почему вы испытываете зависание пользовательского интерфейса.

Если вы используете backgroundWorker для выполнения трудоемкой задачи, вы сможете достичь того, чего хотите. Вы должны реализовать логику в предложении while(true) в методе BackgroundWorkder.DoWork .

Несколько замечаний о BackgroundWorker ...

DoWork в другом потоке, уведомление о ходе выполнения в главном потоке и отмена асинхронного процесса - самые важные функции в BackgroundWorker. Приведенный ниже пример демонстрирует эти три функции довольно четко. В сети доступно множество примеров.

using System;
using System.Threading;
using System.ComponentModel;

class Program
{
  static BackgroundWorker _bw;

  static void Main()
  {
    _bw = new BackgroundWorker
    {
      WorkerReportsProgress = true,
      WorkerSupportsCancellation = true
    };
    _bw.DoWork += bw_DoWork;
    _bw.ProgressChanged += bw_ProgressChanged;
    _bw.RunWorkerCompleted += bw_RunWorkerCompleted;

    _bw.RunWorkerAsync ("Hello to worker");

    Console.WriteLine ("Press Enter in the next 5 seconds to cancel");
    Console.ReadLine();
    if (_bw.IsBusy) _bw.CancelAsync();
    Console.ReadLine();
  }

  static void bw_DoWork (object sender, DoWorkEventArgs e)
  {
    for (int i = 0; i <= 100; i += 20)
    {
      if (_bw.CancellationPending) { e.Cancel = true; return; }
      _bw.ReportProgress (i);
      Thread.Sleep (1000);      // Just for the demo... don't go sleeping
    }                           // for real in pooled threads!

    e.Result = 123;    // This gets passed to RunWorkerCompleted
  }

  static void bw_RunWorkerCompleted (object sender,
                                     RunWorkerCompletedEventArgs e)
  {
    if (e.Cancelled)
      Console.WriteLine ("You canceled!");
    else if (e.Error != null)
      Console.WriteLine ("Worker exception: " + e.Error.ToString());
    else
      Console.WriteLine ("Complete: " + e.Result);      // from DoWork
  }

  static void bw_ProgressChanged (object sender,
                                  ProgressChangedEventArgs e)
  {
    Console.WriteLine ("Reached " + e.ProgressPercentage + "%");
  }
}

Смотрите здесь для более подробной информации.

0 голосов
/ 10 августа 2015

Подумайте об использовании async-await для обработки ввода и обновления результата, пока ваш поток пользовательского интерфейса выполняет другие действия.

Обработчик событий:

private async void OnButton1_clicked(object sender, ...)
{
    var result = await ProcessInputAsync(...)
    displayResult(result);
}

Предполагая, что ProcessInputAsync является трудоемкой функцией.DisplayResult вызывается потоком пользовательского интерфейса и может обрабатываться нормально.

Примечание: все асинхронные функции должны возвращать Task вместо void или Task <Tresult> вместо TResult.Есть одно исключение: асинхронные обработчики событий должны возвращать void вместо Task.

private async Task<TResult> ProcessInputAsync(...)
{
    return await Task.Run( () => LengthyProcess(...)
}

private TResult LengthyProcess(...)
{
    // this is the time consuming process.
    // it is called by a non-ui thread
    // the ui keeps responsive
    TResult x = ...
    return x;
 }

Если вы действительно не хотите ждать завершения длинного процесса, но хотите, чтобы другой потокпри обновлении пользовательского интерфейса вы получаете ошибку во время выполнения, что поток, который не создал элемент пользовательского интерфейса, пытается его обновить.Для этого у нас есть шаблон вызова:

private void UpdateMyTextBox(string myTxt)
{
    if (this.InvokeRequired)
    {   // any other thread than the UI thread calls this function
        // invoke the UI thread to update my text box
        this.Invoke(new MethodInvoker(() => this.UpdateMyTextBox(myTxt));
    }
    else
    {
        // if here: this is the UI thread, we can access the my text box
        this.TextBox1.Text = myTxt;
    }
}
0 голосов
/ 21 сентября 2011

Элементы управления Windows формы не могут быть доступны из отдельного потока напрямую. Возможно, вы захотите использовать Control.Invoke для изменения свойств текстового поля / таблицы данных
Прочтите статью MSDN. о доступе к элементам управления из отдельного потока.

0 голосов
/ 21 сентября 2011

Я бы предположил, что основной (GUI) поток зависает из-за цикла (неясно, обрабатываете ли вы какие-то события там).Также, чтобы изменить графический интерфейс из другого потока, вы должны вызвать Invoke с делегатом, изменяющим желаемые значения.

...