2009-11-30 4 views
0

Чтобы немного поиграть с потоками, делегатами и работниками фонового рисунка, я собираю несколько небольших приложений, у меня проблемы с одним из них. У меня есть форма Windows, с текстовым полем, кнопкой и богатым текстом. При нажатии на кнопку, текст в текстовом поле используется в качестве параметра для создания экземпляра класса, например:C# Threading issue

public partial class Form1 : Form 
{ 
    private BackgroundWorker backgroundWorker; 

    public Form1() 
    { 
     InitializeComponent();    
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork); 
     backgroundWorker.RunWorkerAsync(); 
    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     new Thread((ThreadStart)delegate() 
     { 
      this.BeginInvoke((ThreadStart)delegate() 
      { 
       foreach (string line in textBox1.Lines) 
       { 
        Dig digger = new Dig(line, textBox1.Text); 
        digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker); 

        string response = digger.GetAllInfo(); 

        richTextBox1.AppendText(response); 
        Application.DoEvents(); 
       } 
      }); 
     }).Start(); 
    } 

    void OnUpdateTicker(string msg) 
    { 
     new Thread((ThreadStart)delegate() 
     { 
      this.BeginInvoke((ThreadStart)delegate() 
      { 
       label4.Text = msg; 
       Application.DoEvents(); 
      }); 
     }).Start();    
    } 
} 

При отладке я бегу в «textBox1.Lines» бросил исключение типа ' Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException ' Любые советы о том, как решить эту проблему?

ответ

5

Во-первых, нет необходимости создавать новые потоки внутри DoWork; вся идея с BackgroundWorker заключается в том, что DoWork выполняется на отдельном потоке. Во-вторых, поскольку DoWork выполняется в отдельном потоке, и элементы управления пользовательского интерфейса могут быть изменены только в потоке пользовательского интерфейса, вам необходимо правильно их активировать. Таким образом, переписана версия worker_DoWork может выглядеть следующим образом:

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    foreach (string line in textBox1.Lines) 
    { 
     Dig digger = new Dig(line, textBox1.Text); 
     digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker); 
     string response = digger.GetAllInfo(); 
     richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); }); 
    } 
} 

Обратите внимание, как код не явно нерест новые темы, а также, как это делается вызов AppendText метод через Control.Invoke вызов, заставляя его выполнять на поток пользовательского интерфейса.

0

Основная причина в том, что текстовое поле не принадлежит фоновому потоку.

Ваш пользовательский интерфейс имеет все объекты пользовательского интерфейса, и при нажатии кнопки вы вращаете фоновый поток. Этот фоновый поток не должен иметь доступа к каким-либо объектам пользовательского интерфейса.

Если вы хотите, чтобы значение текстового поля использовалось, вам нужно передать его в фоновый поток другим способом.

Have a look here for an explanation (and solution).

0

можно обновлять только элементы управления в главном потоке от самого главного потока, если вы явно не сказать программе, что это нормально сделать, используя метод .Invoke элемента управления.

From: http://www.albahari.com/threading/part3.aspx 

Control.Invoke

В многопоточном Windows Forms приложения, это незаконно, чтобы вызвать метод или свойство элемента управления из любого другого потока, чем тот, который его создал. Все вызовы с перекрестными потоками должны быть явно привязаны к потоку, который создал элемент управления (обычно основной поток), используя метод Control.Invoke или Control.BeginInvoke. Нельзя полагаться на автоматическое сортирование, потому что это происходит слишком поздно - только тогда, когда исполнение становится хорошо неуправляемым, и к тому времени уже существует много внутреннего кода .NET, который может быть запущен на «неправильном» потоковом коде, который не является потокобезопасным.