这个问题在这里已有答案:
在我的Windows窗体中我有一个文本框和一个按钮,文本框“tb_LogBox”是多行文本框我试图创建一个后台工作者,应该调用一个函数,即我编译时的“LogTimer.DnT()”是并运行它Visual Studio抛出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 + " =@= " + 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);
}
}
6 回答
尝试使用begin invoke方法:
这比Invoke更顺畅 .
你需要将Ui更改编组到UI线程上 . 这可以通过使用tb_LogBox.AppendText周围的invoke / begininvoke调用来执行
在Winforms应用程序中:
在WPF应用程序中:
希望这可以帮助!
在ExecuteOperations中执行此操作:
您不能使用其他线程(BackgroundWorker使用.NET线程池线程)来更改UI组件 . 这是您在WinForms编程中习惯的主要障碍 .
您需要在UI线程上调用控件的方法:
我不知道
LogTimer
的作用,但很可能你也应该在委托中创建它:BackgroundWorker在其自己的线程上执行,与WinForms GUI元素相关的所有操作必须在创建它们的线程上运行 . 它们当前使用的方式BackgroundWorker与使用ThreadPool.QueueUserWorkItem()对操作进行排队相同 . 要使用BackgroundWorker与GUI进行通信,请使用ReportProgess或在worker方法中设置DoWorkEventArgs.Result属性,并对GUI线程上的相应事件做出反应 . 您还可以在WinForms控件上使用Invoke / BeginInvoke直接在GUI线程上执行任意代码 . 在您的情况下,这将意味着替换访问tb_LogBox的行:
您无法从后台工作程序的执行线程访问主机线程 . 您可以使用BackgroundWorker的ReportProgress方法将信息发送到主机线程 .