Control de subprocesos. Invocar

Tengo una función

public void ShowAllFly() { cbFly.Items.Clear(); cbFly.Items.Add("Uçuş Seçiniz..."); dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); dsFly _mds = new dsFly(); _mds.EnforceConstraints = false; dsFly.tblFlyDataTable _m = _mds.tblFly; _t.Fill(_m); foreach (DataRow _row in _m.Rows) { cbFly.Items.Add(_row["FlyID"].ToString()+"-"+_row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString()); } _Thread.Abort(); timer1.Enabled = false; WaitPanel.Visible = false; } 

En la función Form_Load Me gusta esto;

 { _Thread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowAllFly)); _Thread.Start(); _Thread.Priority = System.Threading.ThreadPriority.Normal; } 

Pero cuando lo ejecuto;

en la función ShowAllFly

 cbFly.Items.Clear(); ---- HERE Gives ERROR LIKE Control.Invoke must be used to interact with controls created on a separate thread. 

¿Cuál es el problema?

Hay dos reglas de oro para enhebrar en Windows Forms:

  • No toque ninguna propiedad o método de control (que no sean los explícitamente enumerados como correctos) de un hilo que no sea el que creó el “control” del control (generalmente solo hay un hilo de UI)
  • No bloquee el hilo de la interfaz de usuario durante un período de tiempo significativo, o hará que la aplicación no responda

Para interactuar con la interfaz de usuario desde un hilo diferente, necesita “ordenar” la llamada a la BeginInvoke interfaz de usuario, usar un delegado y llamar a Control.Invoke / BeginInvoke . Puede probar si necesita llamar a Invoke utilizando la propiedad InvokeRequired , pero en estos días, personalmente, solo lo hago de todos modos: no hay muchas penalidades por invocar cuando no es necesario.

Las expresiones Lambda en C # 3 (o métodos anónimos en C # 2) hacen que esto sea mucho más agradable también.

Por ejemplo, podrías usar:

 cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear())); 

Todos los corchetes se interponen un poco, por lo que es posible que desee agregar un método de extensión como este, si está utilizando C # 3:

 public static void Invoke(this Control control, MethodInvoker action) { control.Invoke(action); } 

Entonces podrías hacer:

 cbFly.Invoke(() => cbFly.Items.Clear()); 

que es mucho más simple. Por lo general, puedes salirte con la MethodInvoker utilizando MethodInvoker al capturar cualquier variable a la que necesites acceder dentro del delegado.

Ver mi tutorial de subprocesos o Joe Albahari para más detalles.

Como una cuestión secundaria, veo que estás usando Thread.Abort , de hecho en tu propio hilo, a pesar de tener otras llamadas después de él. ¿Por qué? Anular cualquier hilo que no sea ​​el suyo es una llamada de tipo “solo emergencias” (que generalmente debe ser seguida por la aplicación que se descarga de todos modos) y no veo ninguna razón para abortar el hilo actual cuando aún queda trabajo por hacer después. ..

La interacción en los controles en otro subproceso (ui) debe invocarse de la siguiente manera:

 public delegate void ProcessResultDelegate(string result); void ProcessResult(string result) { if (textBox1.InvokeRequired) { var d = new ProcessResultDelegate(ProcessResult); d.Invoke(result); } else { textBox1.Text = result; } } 

Siempre he encontrado este artículo útil en este tema en particular.

En su ejemplo, intenta modificar varios controles de un hilo que no creó el control. Para evitar este problema dado su ejemplo, haga esto en su lugar (suponiendo que el método ShowAllFly () es un método en su formulario):

 public void ShowAllFly() { Invoke((MethodsInvoker) delegate { cbFly.Items.Clear(); cbFly.Items.Add("Uçuş Seçiniz..."); dsFlyTableAdapters.tblFlyTableAdapter _t = new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); dsFly _mds = new dsFly(); _mds.EnforceConstraints = false; dsFly.tblFlyDataTable _m = _mds.tblFly; _t.Fill(_m); foreach (DataRow _row in _m.Rows) { cbFly.Items.Add(_row["FlyID"].ToString() + "-" + _row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString()); } //_Thread.Abort(); // WHY ARE YOU TRYING TO DO THIS? timer1.Enabled = false; WaitPanel.Visible = false; } ); } 

Solo para enfatizar el punto que hizo @Jon Skeet, comenté la llamada para abortar el hilo. El hilo terminará por sí mismo. No hay razón para abortar de esta manera.

Debe ser invocado … Pero invoque tiene que esperar el hilo principal Quiero decir que no obtiene el error de esta manera, pero esto no funciona paralelamente si quiere ir a más de un proceso al mismo tiempo, simplemente cree más de un hilo

 Thread thread = new Thread(new delegate_method(method));//you must create delegate before thread.start (); Thread thread2 = new Thread(new delegate_method(method2));//you must create delegate before thread.start (); 

manejar dos procesos al mismo tiempo

  void method () { //do something here -- working background Remember can not control any UI control from here finish_thread() } void method2 () { //do something here -- working background Remember can not control any UI control from here finish_thread() } void finish_thread() { if(invoke.Required) { //Here you have to call delegate method here with UI BeginInvoke(new delegate_method(finish_thread)); } else { //Now you can control UI thread from here and also you finished background work //Do something working with UI thread textBox.Text = ""; } }