C# 跨线程:从不同线程访问控件

C# 跨线程:从不同线程访问控件,c#,.net,winforms,multithreading,C#,.net,Winforms,Multithreading,我认为代码说得很清楚 private void ucPerson_Load(object sender, EventArgs e) { person = new Person(); BackgroundWorker backgroundBinder = new BackgroundWorker(); backgroundBinder.DoWork += BindComboBoxes; backgroundBinder.RunWorkerAsync(); } pr

我认为代码说得很清楚

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”。


我需要做什么才能让我的
后台工作线程访问combobox?

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

后台工作线程在另一个线程中工作:不允许您调用属于其中调用线程的控件

正如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;
}
private void ucPerson\u加载(对象发送方,事件参数e)
{
person=新的person();
BackgroundWorker backgroundBinder=新的BackgroundWorker();
backgroundBinder.DoWork+=GetData;
backgroundBinder.RunWorkerCompleted+=BindComboBox;
backgroundBinder.RunWorkerAsync();
}
来源;
私有void GetData(对象发送方,DoWorkEventArgs e)
{
source=Program.eService.GetEducationLevel();
}
专用void bindcomboxes(对象发送方、RunWorkerCompletedEventArgs e)
{
cmbNational.DisplayMember=“名称”;
cmbNationary.ValueMember=“NationalityID”;
cmbNationalty.DataSource=源;
}

最好的方法是以劳伦特为例

肮脏的方式:

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

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

在工作程序完成运行后,您必须将
数据源的分配过账到。@UweKeim如何才能知道工作程序何时完成运行?你能给我举个例子吗?
RunWorkerCompleted
被激发到你的前台线程。因此,在这个处理程序中进行工作,就像您接受的答案一样,是一个好方法。从后台线程调用,尤其是从后台工作线程调用,对我来说似乎是一个糟糕的设计决策。谢谢Laurent,祝您好运。不客气;我假设Program.eService.GetEducationLevel()需要很长时间;)是的,事实上,我们正在考虑用户可能正在使用慢速连接,这就是我们使用web服务的原因。谢谢