【问题标题】:Cross-threading: Accessing a control from a different thread [duplicate]跨线程:从不同的线程访问控件[重复]
【发布时间】:2013-02-06 12:56:32
【问题描述】:

我认为代码很清楚

private void ucPerson_Load(object sender, EventArgs e)
{
    person = new Person();
    BackgroundWorker backgroundBinder = new BackgroundWorker();
    backgroundBinder.DoWork += BindComboBoxes;
    backgroundBinder.RunWorkerAsync();
}

private void BindComboBoxes(object sender, DoWorkEventArgs e)
{
    cmbEducationLevel.DataSource = Program.eService.GetEducationLevels();
    cmbNationality.DisplayMember = "Name";
    cmbNationality.ValueMember = "NationalityID";
}

我得到的错误:

跨线程操作无效:控件“cmbNationality”从创建它的线程以外的线程访问。

我需要做些什么才能使我的background-worker 的线程能够访问组合框?

【问题讨论】:

  • 您必须将DataSource 的分配推迟到工作人员完成运行后。
  • @UweKeim 我怎样才能知道工人何时完成运行?你能给我举个例子吗?
  • RunWorkerCompleted 被触发到您的前台线程。因此,就像您接受的答案一样,在此处理程序中进行工作是一种好方法。

标签: c# .net winforms multithreading


【解决方案1】:

backgroundworker在另一个线程中工作:你不能在其中调用属于调用线程的控件。

正如 Uwe Keim 所说,您必须将所有触及控件的内容放在 RunWorkerCompleted 事件中:

private void ucPerson_Load(object sender, EventArgs e)
{
    person = new Person();
    BackgroundWorker backgroundBinder = new BackgroundWorker();
    backgroundBinder.DoWork += GetData;
    backgroundBinder.RunWorkerCompleted += BindComboBoxes;
    backgroundBinder.RunWorkerAsync();
}

<<yourReturnType>> source;

private void GetData(object sender, DoWorkEventArgs e)
{
    source = Program.eService.GetEducationLevels();
}

private void BindComboBoxes(object sender, RunWorkerCompletedEventArgs e)
{
    cmbNationality.DisplayMember = "Name";
    cmbNationality.ValueMember = "NationalityID";
    cmbNationalty.DataSource = source;
}

【讨论】:

  • 感谢 Laurent,祝你好运。
  • 不客气;我假设 Program.eService.GetEducationLevels() 需要很长时间;)
  • 是的,实际上我们考虑到用户可能正在使用慢速连接,这就是我们使用 Web 服务的原因。谢谢。
【解决方案2】:

最好的方法是 Laurent 的例子

肮脏的方式:

cmbEductionLevel.Invoke((MethodInvoker)delegate { mbEducationLevel.DataSource = Program.eService.GetEducationLevels(); });

cmbNationality.Invoke((MethodInvoker)delegate { 
     cmbNationality.DisplayMember = "Name";
     cmbNationality.ValueMember = "NationalityID"; 
});

【讨论】:

    【解决方案3】:

    您应该使用 Invoke 并传递一个委托来更新控件。

    【讨论】:

    • 从后台线程调用,尤其是后台工作线程,对我来说似乎是一个糟糕的设计决定。
    猜你喜欢
    • 2016-12-20
    • 1970-01-01
    • 2021-06-28
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2011-01-15
    相关资源
    最近更新 更多