2009-05-29 13 views
7

Este código siguiente me da el siguiente error. Creo que necesito "InvokeRequired". Pero no entiendo cómo puedo usar?¿Cómo puedo corregir el error "accedido desde un hilo que no sea el hilo en el que se creó"?

Operación entre hilos no válida: Controle 'listBox1' al que se accede desde un hilo que no sea el hilo en el que se creó.

El código:

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace WindowsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     protected static DataSet dataset = null; 
     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 
      SimulationFrameWork.MCSDirector run = new SimulationFrameWork.MCSDirector(); 
      DataSet ds = run.Get(); 

      if (ds.Tables[0].Rows.Count > 0) 
      { 
       for (int i = 0; i < ds.Tables[0].Rows.Count; i++) 
       { 
        if (ds.Tables[0].Rows[i]["result"].ToString() == "0") 
        { 
         dataset = run.Get(int.Parse(ds.Tables[0].Rows[i]["ID"].ToString())); 
         WorkerObject worker = 
         new WorkerObject(
          int.Parse(dataset.Tables[0].Rows[i]["ID"].ToString()), 
          int.Parse(dataset.Tables[0].Rows[i]["Iteration"].ToString()), 
          listBox1, timer1); 
         Thread thread1 = new Thread(new ThreadStart(worker.start)); 
         thread1.Start(); 
        } 
       } 
      } 
     } 
    } 

    public class WorkerObject 
    { 
     private int id; 
     private int nmax; 
     private ListBox list1; 
     private System.Windows.Forms.Timer timer1; 

     public WorkerObject(int _id, int _nmax, ListBox _list1, 
          System.Windows.Forms.Timer _timer1) 
     { 
      id = _id; 
      nmax = _nmax; 
      list1 = _list1; 
      timer1 = _timer1; 
     } 
     public void start() 
     { 
      timer1.Stop(); 
      int i, idaire, j; 
      double pi = 0.0, x, y; 

      Random rnd = new Random(); 
      for (i = 0; i < 100; i++) 
      { 
       idaire = 0; 
       for (j = 0; j < nmax; j++) 
       { 
        x = rnd.Next(1, 10000)/(double)10000; 
        y = rnd.Next(1, 10000)/(double)10000; 
        if (Math.Pow(x, 2) + Math.Pow(y, 2) <= 1.0) 
         idaire += 1; 
       } 
       pi = 4 * (double)idaire/(double)nmax; 
       nmax *= 10; 

       list1.Items.Add(
        "Iterasyon:" + 
        nmax.ToString() + 
        " ----->" + 
        pi.ToString() + 
        "\n"); 
       System.Threading.Thread.Sleep(100); 
      } 
      SimulationFrameWork.MCSDirector run = new SimulationFrameWork.MCSDirector(); 
      run.Update(id, pi); 
      list1.Items.Add("\n\n islem bitti..."); 
     } 
    } 
} 
+0

También echa un vistazo a esta solución en su problema; uno muy elegante: http://stackoverflow.com/questions/906057/problem-with-delegate-syntax-in-c/906097#906097 –

Respuesta

10

Sólo encapsulan añadiendo el texto al cuadro de lista a otro método:

private void timer1_Tick(object sender, EventArgs e) 
{ 
    // ... 
    AddTextToListBox("\n\n işlem bitti..."); 
} 

private void AddTextToListBox(string text) 
{ 
    if(list1.InvokeRequired) 
    { 
     list1.Invoke(new MethodInvoker(AddTextToListBox), new object[] { text }); 
     return; 
    } 

    list1.Items.Add(text); 
} 
+4

Según este enlace: http://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker.aspx no puede use el delegado de MethodInvoker con métodos con parámetros en .NET 4. Si está buscando la respuesta a esta pregunta, consulte la solución de OneSHOT a continuación. –

15

Esto debe ir a todos lados que

private delegate void stringDelegate(string s); 
private void AddItem(string s) 
{ 
    if (list1.InvokeRequired) 
    { 
     stringDelegate sd = new stringDelegate(AddItem); 
     this.Invoke(sd, new object[] { s }); 
    } 
    else 
    { 
     list1.Items.Add(s); 
    } 
} 

Sólo tiene que llamar AddItem y esto invocará el complemento utilizando un delegado si es necesario de lo contrario, sólo tiene que añadir el artículo directamente a la caja.

OneShot

+0

Acabo de notar que su código también tiene un parásito "en la línea para (int i = 0; i "+ pi.ToString() +" \ n "); justo después (int i = 0; i – OneSHOT

+2

Declarar delegados adicionales no es necesario; puede hacerlo utilizando simplemente MethodInvoker ... –

+0

¿Hay algún método simple? DoWork, ProgressChanged, RunWorkerCompleted – Penguen

-4

añadir este código antes de iniciar el hilo:

//kolay gelsin kardeş) 
CheckForIllegalCrossThreadCalls = false; 
thread1.Start(); 
+3

No es una buena idea. xcepción a cambio de errores impredecibles y espectaculares. –

0

También puede utilizar la notación lambda. Así, en lugar de:

formControl.Field = newValue; //Causes error 

Probar:

Invoke(new Action(() => 
{ 
    formControl.Field = newValue; //No error 
})); 
Cuestiones relacionadas