2009-10-20 6 views
0

В моей форме окна у меня есть текстовое поле и кнопка, текстовое поле «tb_LogBox» - это многострочное текстовое поле. Я пытаюсь создать фона рабочего, который должен вызывать функцию, LogTimer.DnT() ", когда я компилирую и запускаю его, Visual Studio выбрасывает InvalidOperationException.C# InvalidOperationException И операция с поперечными потоками

Фактическая ошибка, с которой я получаю Неверная операция кросс-потоков: элемент управления 'tb_LogBox' доступен из потока, отличного от потока, на котором он был создан. Следующий пример кода иллюстрирует то, что я пытаюсь сделать

private void button1_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     var bw = new BackgroundWorker(); 
     bw.DoWork += ExecuteOperations ; 
     bw.RunWorkerAsync(); 
    } 
    catch (Exception ex) 
    { 
     tb_LogBox.AppendText(Environment.NewLine + " [email protected]= " + ex.Message+" "+ex.Source); 
    } 
} 

private void ExecuteOperations(object sender, DoWorkEventArgs e) 
{ 
    var FuncCall = new LogTimer(); 
    tb_LogBox.AppendText(Environment.NewLine + FuncCall.DnT()); // the line i am getting the error. on 
} 

public class LogTimer 
{ 
    public string DnT() 
    { 
     const string datePat = @"d/MM/yyyy"; 
     var dateTime = DateTime.Now(); 
     return dateTime.ToString(datePat); 
    } 
} 

ответ

4

Попробуйте использовать метод начать Invoke:

BeginInvoke(new Action(() => 
    { 
     tb_LogBox.AppendText(Environment.NewLine + FuncCall.DnT()); 
    })); 

Это будет более гладкой, чем Invoke.

0

Вам нужно вызвать метод элемента управления в потоке пользовательского интерфейса:

private void ExecuteOperations(object sender, DoWorkEventArgs e) 
{ 
    var FuncCall = new LogTimer(); 
    tb_LogBox.Invoke((MethodInvoker)delegate{ 
     tb_LogBox.AppendText(Environment.NewLine + FuncCall.DatenTime()); 
    }); 
} 

Я не знаю, что LogTimer делает, но это может очень а в том, что вы должны создать что внутри делегата, а также:

private void ExecuteOperations(object sender, DoWorkEventArgs e) 
{ 
    tb_LogBox.Invoke((MethodInvoker)delegate{ 
     var FuncCall = new LogTimer(); 
     tb_LogBox.AppendText(Environment.NewLine + FuncCall.DatenTime()); 
    }); 
} 
1

ли это в ваших ExecuteOperations:

tb_LogBox.Invoke((MethodInvoker)delegate() { tb_LogBox.AppendText(...) })); 

Вы не можете использовать другие темы (BackgroundWorker использует поток .NET threadpool), чтобы вносить изменения в компоненты пользовательского интерфейса. Это основное препятствие, с которым вам придется привыкнуть в программировании WinForms.

2

вам необходимо изменить марку Ui на нить пользовательского интерфейса. Это может быть осуществлено с помощью/BeginInvoke вызова Invoke вокруг tb_LogBox.AppendText

в Winforms Применении:

this.BeginInvoke((MethodInvoker)delegate 
     { 
      tb_LogBox.AppendText(Environment.NewLine + FuncCall.DatenTime()); 
     }); 

в приложении WPF:

this.Dispatcher.BeginInvoke(
     (Action)delegate() 
     { 
      tb_LogBox.AppendText(Environment.NewLine + FuncCall.DatenTime()); 
     }); 

Надеется, что это помогает!

0

BackgroundWorker выполняет на своем собственном потоке, и все операции, связанные с элементами интерфейса WinForms, должны выполняться в потоке, в котором они были созданы. Они, как вы в настоящее время используете BackgroundWorker, идентичны только для Queuing операции с помощью ThreadPool.QueueUserWorkItem(). Для обратной связи с графическим интерфейсом с помощью BackgroundWorker используйте ReportProgess или установите свойство DoWorkEventArgs.Result в рабочем методе и отреагируйте на соответствующие события в потоке графического интерфейса. Вы также можете использовать Invoke/BeginInvoke в элементе управления WinForms для выполнения произвольного кода непосредственно в потоке графического интерфейса. В вашем случае это будет означать, заменив строку с доступом к tb_LogBox с:

tb_LogBox.Invoke(new Action(() => 
    tb_LogBox.AppendText(Environment.NewLine + FuncCall.DatenTime()); 
)); 
0

Вы не можете получить доступ к хост-нити из потока выполнения фоновой работники. Вы можете использовать метод ReportProgress для BackgroundWorker для отправки информации в поток хоста.

private void button1_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     var bw = new BackgroundWorker(); 
     bw.DoWork += ExecuteOperations; 
     bw.ProgressChanged += bw_ProgressChanged; 
     bw.RunWorkerAsync(); 
    } 
    catch (Exception ex) 
    { 
     tb_LogBox.AppendText(Environment.NewLine + " [email protected]= " + ex.Message + " " + ex.Source); 
    } 
} 

private static void ExecuteOperations(object sender, DoWorkEventArgs e) 
{ 
    var FuncCall = new LogTimer(); 
    string text = Environment.NewLine + FuncCall.DnT(); 

    (sender as BackgroundWorker).ReportProgress(0, text); 
} 
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    tb_LogBox.AppendText(e.UserState as string); 
} 

public class LogTimer 
{ 
    public string DnT() 
    { 
     const string datePat = @"d/MM/yyyy"; 
     var dateTime = DateTime.Now; 
     return dateTime.ToString(datePat); 
    } 
} 
Смежные вопросы