2009-05-29 10 views
7

Questo codice seguente mi dà l'errore qui sotto. Penso di aver bisogno di "InvokeRequired". Ma non capisco come posso usare?Come posso correggere l'errore "accesso da un thread diverso dal thread su cui è stato creato"?

Operazione cross-thread non valida: controllo 'elencoBox1' a cui si accede da un thread diverso dal thread su cui è stato creato.

Il codice:

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

Verificate anche questa soluzione sul problema; uno molto elegante: http://stackoverflow.com/questions/906057/problem-with-delegate-syntax-in-c/906097#906097 –

risposta

10

Proprio incapsulare l'aggiunta del testo per la casella di riepilogo a un altro metodo:

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

Secondo questo link: http://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker.aspx non puoi utilizzare MethodInvoker delegato con metodi con parametri in .NET 4. Se si sta cercando la risposta a questa domanda, controllare la soluzione di OneSHOT in basso. –

15

Questo dovrebbe farti intorno ad esso

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); 
    } 
} 

Basta chiamare AddItem e questo richiamerà il componente aggiuntivo tramite un delegato, se è necessario, altrimenti sarà solo aggiungere l'oggetto direttamente nella scatola.

OneShot

+0

Appena notato che il tuo codice ha anche un randagio "on line per (int i = 0; i "+ pi.ToString() +" \ n "); subito dopo (int i = 0; i – OneSHOT

+2

La dichiarazione di delegati aggiuntivi non è necessaria; è possibile farlo utilizzando solo MethodInvoker ... –

+0

esiste un metodo semplice: DoWork, ProgressChanged, RunWorkerCompleted – Penguen

-4

aggiungere questo codice prima di iniziare la discussione:

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

Non è una buona idea. Ciò impedirebbe la xception in cambio di errori imprevedibili e spettacolari. –

0

è anche possibile utilizzare la notazione lambda. Così, invece di:

formControl.Field = newValue; //Causes error 

Prova:

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