2009-05-29 5 views
7

Poniższy kod zawiera błąd poniżej. Myślę, że potrzebuję "InvokeRequired". Ale nie rozumiem, w jaki sposób mogę użyć?Jak mogę poprawić błąd "uzyskany z wątku innego niż wątek, w którym został utworzony"?

Nieprawidłowe działanie wątku krzyżowego: Kontrola "listBox1" uzyskana z wątku innego niż wątek, w którym został utworzony.

Kod:

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

także sprawdzić to rozwiązanie na swój problem; bardzo elegancki: http://stackoverflow.com/questions/906057/problem-with-delegate-syntax-in-c/906097#906097 –

Odpowiedz

10

Wystarczy hermetyzacji dodanie tekstu do pola listy do innej metody:

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

Zgodnie z tym linkiem: http://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker.aspx nie możesz użyj delegata MethodInvoker z metodami o parametrach w .NET 4. Jeśli szukasz odpowiedzi na to pytanie, sprawdź rozwiązanie OneSHOT poniżej: –

15

To powinno Ci wokół niego

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

Wystarczy zadzwonić AddItem a to wywoła dodatek używając delegata, jeśli jest to wymagane w przeciwnym razie będzie to tylko dodatek przedmiot bezpośrednio do pudełka.

Oneshot

+0

Po prostu zauważyłem, że twój kod ma również zabłąkany "on the line for (int i = 0; i "+ pi.ToString() +" \ n "); just after (int i = 0; i – OneSHOT

+2

Zgłaszanie dodatkowych delegatów jest niepotrzebne, możesz to zrobić za pomocą metody MethodInvoker ... –

+0

czy istnieje metoda w prosty sposób: DoWork, ProgressChanged, RunWorkerCompleted – Penguen

-4

Dodaj ten kod przed rozpoczęciem wątek:

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

To nie jest dobry pomysł, ponieważ zapobiegnie deterministycznym wykroczenie w zamian za nieprzewidywalne i spektakularne błędy. –

0

można również użyć notacji lambda. Tak więc, zamiast:

formControl.Field = newValue; //Causes error 

Spróbuj:

Invoke(new Action(() => 
{ 
    formControl.Field = newValue; //No error 
})); 
Powiązane problemy