繁体   English   中英

如何使用异步从C#中的另一个线程更新WinForm中的某些GUI控件

[英]How to update some GUI control in a WinForm from another thread in C# using async

我正在尝试从第二个线程更新某些GUI控件的文本,但是Visual Studio显示了一个异常:

System.Windows.Forms.dll中发生类型为“ System.InvalidOperationException”的异常,但未在用户代码中处理

附加信息:

通过子流程进行的无效操作:对“ impPROF_combo”的访问从他创建的线程之外的其他线程获得了控制权。


我的代码是:

    private async void checkBox1_CheckedChanged(object sender, EventArgs e)
    {

        sciLoadingCircle1.Visible = true;
        sciLoadingCircle1.Active = true;

        await Task.Run(() => refreshComboColumnsNames());

        sciLoadingCircle1.Visible = false;
        sciLoadingCircle1.Active = false;

    }
    private void refreshComboColumnsNames()
    {
        object[] columnsNames = this.generateComboColumnsNames();
        int impPROF_combo_selected = impPROF_combo.SelectedIndex; //the exceptions  throws from here 
        impPROF_combo.Items.Clear();

        impPROF_combo.Items.AddRange(columnsNames);

        impPROF_combo.SelectedIndex = impPROF_combo_selected;
    }

我怎样才能正确地做到这一点? 谢谢。

UI组件只能从其UI线程访问。 在这种情况下,您将在Task.Run放入太多代码:

private async void checkBox1_CheckedChanged(object sender, EventArgs e)
{
  sciLoadingCircle1.Visible = true;
  sciLoadingCircle1.Active = true;

  await refreshComboColumnsNamesAsync();

  sciLoadingCircle1.Visible = false;
  sciLoadingCircle1.Active = false;
}

private async Task refreshComboColumnsNamesAsync()
{
  object[] columnsNames = await Task.Run(() => this.generateComboColumnsNames());
  int impPROF_combo_selected = impPROF_combo.SelectedIndex;
  impPROF_combo.Items.Clear();
  impPROF_combo.Items.AddRange(columnsNames);
  impPROF_combo.SelectedIndex = impPROF_combo_selected;
}

为了从另一个线程更新GUI(或使用)元素,您应该使用Control.BeginInvoke() https://msdn.microsoft.com/ru-ru/library/system.windows.forms.control.begininvoke ( v= vs .110).aspx,以及如何使用它。 如何使用BeginInvoke C#

您想要在GUI线程以外的线程中执行某些代码的通常原因是,该操作需要大量时间才能完成并阻塞GUI线程。

我可以看到refreshComboColumnsNames方法的代码的唯一线,这可能需要时间- generateComboColumnsNames 其他语句是GUI更新操作,必须在GUI线程中执行。 据我了解, generateComboColumnsNames做一些繁重的计算或执行数据库查询或发送http请求或执行任何其他长操作。 此操作的结果需要在UI中显示。 纠正我,如果我错了。

我建议使generateComboColumnsNames异步运行,该操作在单独的线程中执行。 此操作不得更新UI-仅返回数据。 结果如下所示:

private async void checkBox1_CheckedChanged(object sender, EventArgs e)
{
    sciLoadingCircle1.Visible = true;
    sciLoadingCircle1.Active = true;

    await refreshComboColumnsNames();

    sciLoadingCircle1.Visible = false;
    sciLoadingCircle1.Active = false;

}

private async Task refreshComboColumnsNames()
{
    object[] columnsNames = await this.generateComboColumnsNames();

    int impPROF_combo_selected = impPROF_combo.SelectedIndex;             
    impPROF_combo.Items.Clear();
    impPROF_combo.Items.AddRange(columnsNames);
    impPROF_combo.SelectedIndex = impPROF_combo_selected;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM