Как избежать зависания графического интерфейса во время цикла? - PullRequest
0 голосов
/ 06 ноября 2019

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

double MeasNoAvgwrapper()
{
    double temp = 0D;
    double[] tempList = new double [MeasNoAvg];

    for(int t = 0; t < MeasNoAvg; t++)
    {
        tempList[t] = AveragePixeLink2();
    }

    temp = tempList.Average();

    return temp;
}

Кто-нибудь видит что-то не так с этим?

1 Ответ

0 голосов
/ 06 ноября 2019

С WinForms вы можете использовать это, чтобы позволить Application отправлять события и обновлять графический интерфейс, при этом отключая форму, чтобы запретить взаимодействие с пользователем и изменять курсор мыши, если вам нужно:

Cursor = Cursors.WaitCursor;  // for UX
Enabled = false;              // for UX
try
{
  for ( int t = 0; t < MeasNoAvg; t++ )
  {
    tempList[t] = AveragePixeLink2();
    Refresh();
    Application.DoEvents();   // for UI
  }
  temp = tempList.Average();
}
finally
{
  Enabled = true;
  Cursor = Cursors.Default;
}

Вы также можете добавить кнопку «Отмена», отключенную по умолчанию, чтобы разрешить остановить процесс с помощью условной переменной.

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

private bool CancelRequired;
SetFormEnabled(false);
Cursor = Cursors.WaitCursor;
CancelRequired = false;
ButtonCancel.Enabled = true;
try
{
  for ( int t = 0; t < MeasNoAvg; t++ )
  {
    if ( CancelRequired ) break;
    tempList[t] = AveragePixeLink2();
    Refresh();
    Application.DoEvents();
  }
  temp = tempList.Average();
}
finally
{
  CancelRequired = false;
  ButtonCancel.Enabled = false;
  Cursor = Cursors.Default;
  SetFormEnabled(true);
}
private void ButtonCancel_Click(object sender, EventArgs e)
{
  CancelRequired = true;
}

Если процесс занимает время, вы можете использовать индикатор выполнения в форме или в формевсплывающее окно, имеющее значение TopMost true:

SplashForm.cs или текущая форма

public void InitProgress(int stepCount, int stepIncrement)
{
  progressBar.Minimum = 0;
  progressBar.Maximum = stepCount;
  progressBar.Value = 0;
  progressBar.Step = stepIncrement;
}

void DoProgress()
{
  progressBar.PerformStep();
  progressBar.Refresh();
}

Форма вызова

SetFormEnabled(false);
var splash = new SplashForm();
splash.InitProgress(MeasNoAvg, 1);
splash.Show();
CancelRequired = false;
ButtonCancel.Enabled = true;
Cursor = Cursors.WaitCursor;
try
{
  for ( int t = 0; t < MeasNoAvg; t++ )
  {
    if ( CancelRequired ) break;
    tempList[t] = AveragePixeLink2();
    Refresh();
    splash.DoProgress();
    Application.DoEvents();
  }
  temp = tempList.Average();
}
finally
{
  CancelRequired = false;
  ButtonCancel.Enabled = false;
  Cursor = Cursors.Default;
  splash.Close();
  SetFormEnabled(true);
}

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

...