【问题标题】:How to avoid freezing the GUI during a loop?如何避免在循环期间冻结 GUI?
【发布时间】:2020-03-02 14:16:53
【问题描述】:

如果我运行太多数据,我的 GUI 会冻结,即使我的进程正在另一个线程中运行。事实上,即使在 GUI 被锁定的情况下,该线程也会一直运行直到它完成。所以我认为我的代码出了点问题

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

有人发现它有问题吗?

【问题讨论】:

  • 如何调用方法?问题将存在,因为这只是工作函数。并且无法从您显示的代码中推断出问题
  • 如果你从 UI 线程同步调用这个,那么 UI 线程必须等待这个完成才能做任何其他事情(你知道,比如渲染 UI 更改)。跨度>
  • 如何创建和使用线程?

标签: c# loops user-interface memory freeze


【解决方案1】:

使用 WinForms,您可以使用它来允许 Application 调度事件并刷新 GUI,同时禁用表单以禁止用户交互并在需要时更改鼠标光标:

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

如果进度条在主窗体中,去掉splash的使用,最后设置进度条值为0。

【讨论】:

    猜你喜欢
    • 2012-06-27
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    相关资源
    最近更新 更多