关于“线程间操作无效 从不是创建控件“___”的线程访问它”解决方法的疑惑
解决方法根据网友的资料一般提到了两种,但msdn的帮助提到了三种,有一种但我怎么验证也不行。先说一下经常讨论的两种:(1)不使用委托:在构造函数或者窗体Load的代码里添加下面一句:
Control.CheckForIllegalCrossThreadCalls = False
(2)委托方法的实现
private delegate void TestDelegate();
private void DelegateMethod(){
////label......
}
private void StartMethod(){
this.Invoke(new TestDelegate(DelegateMethod))
}
private button_click(...){
Thread thread = new Thread(new ThreadStart(StartMethod));
thread.Start();
}
这两种方法都没有问题,但是msdn还有一种即说用backgroundworker组件,这种方法那个例子没问题。
但是在下面这种情况就出问题了:
我通过串口(serialport)接收数据然后更新文本框,利用backgroundworker实现不成功。
描述一下我的程序,
在界面上放个textbox1,serialport1,backgroundworker1,button1,
然后在串口的datarecived中
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ass1 = Me.SerialPort1.ReadLine() 'ass1为全局变量,接收串口数据,此步没问题
Me.BackgroundWorker1.RunWorkerAsync() '根据msdn我用BackgroundWorker1在textbox1完成显示
End Sub
'在 BackgroundWorker1_RunWorkerCompleted中
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
TextBox1.Text = "This text was set safely by BackgroundWorker." '在textbox1中显示接收数据
End Sub
在执行到 TextBox1.Text = "This text was set safely by BackgroundWorker." 时提示“线程间操作无效 从不是创建控件“Textbox1”的线程访问它”。说明BackgroundWorker组件不能实现跨线程访问。
但是在msdn例子里把 Me.BackgroundWorker1.RunWorkerAsync() 放在一个button的click中却可以正确运行,不提示跨线程访问问题。
是不是BackgroundWorker组件不能避免类似上面描述的串口多线程访问的错误??那BackgroundWorker组件其实用在何种场合??
--------------------编程问答-------------------- 我学的vb.net,但与C#是互通的
我从vb.net给你说一下吧
窗体上有个textbox1控件,
从线程访问textbox1时用以下方法
delegate Sub Settextbox1f(Str as string)'声明对象
Sub SettextBox1(str as string)'访问textbox1
if me.textbox1.InvokeRequired then
Dim d as new Settextbox1f(AddressOf SettextBox1)
me.invoke(d,new object(){str})
else
textbox1.text=str
end sub
调用的时候就用settextbox1(str)就可以了。
--------------------编程问答-------------------- 谢谢,上面的方法我试过了,可以。
不过因为Vb .net中有个backgroundworker组件,msdn介绍说用它实现多线程比较简单也推荐用这种方法,但我测试在串口接收数据时就是不行,所以想问一下backgroundworker组件到底用在何种情况下的多线程跨线程访问才可以? --------------------编程问答-------------------- 顶!我也遇到这个问题,用方法一解决了,不过心理很不舒服。BGWorker组件还没用过,支持楼主。 --------------------编程问答-------------------- 加入form.CheckForIllegalCrossThreadCalls =false --------------------编程问答-------------------- Ding! --------------------编程问答-------------------- 牛X
顶 --------------------编程问答-------------------- 在执行到 TextBox1.Text = "This text was set safely by BackgroundWorker." 时提示“线程间操作无效 从不是创建控件“Textbox1”的线程访问它”。
那是因为BackGroundWorker处于独立于程序主线程的独立线程,无法直接操作窗体上的控件.
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ass1 = Me.SerialPort1.ReadLine() 'ass1为全局变量,接收串口数据,此步没问题
Me.BackgroundWorker1.RunWorkerAsync() '根据msdn我用BackgroundWorker1在textbox1完成显示
End Sub
'在 BackgroundWorker1_RunWorkerCompleted中
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
TextBox1.Text = "This text was set safely by BackgroundWorker." '在textbox1中显示接收数据
End Sub
改成如下试试:
delegate sub AA--------------------编程问答-------------------- 我看了MSDN的例子,backgroundworker根本就不是跨线程访问的。
dim S as String
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ass1 = Me.SerialPort1.ReadLine()
S="This text was set safely by BackgroundWorker."
Me.BeginInvoke(new AA(AdressOf SetText))
End Sub
'在 BackgroundWorker1_RunWorkerCompleted中
Private sub SetText()
TextBox1.Text =S
End Sub
我做了个测试,在BackgroundWorker1_RunWorkerCompleted设置一个死循环会发现整个程序都堵塞在哪里了。说明BackgroundWorker是属于主线程的。
我觉得例子所提的BackgroundWorker只是为了说明安全访问的目的,而没有说明跨线程访问。 --------------------编程问答-------------------- 4楼的方法是我提的第1中解决方法
1,7实际是我提到的第2种方法。
对7楼的一个回答有个疑问
那是因为BackGroundWorker处于独立于程序主线程的独立线程,无法直接操作窗体上的控件.
你的意思是这个BackGroundWorker是不同于主线程和串口接收线程的另外一个线程?出这错的原因是否是因为串口接收线程中调用BackGroundWorker导致的呢?
对8楼的回答一个疑问
我做了个测试,在BackgroundWorker1_RunWorkerCompleted设置一个死循环会发现整个程序都堵塞在哪里了。说明BackgroundWorker是属于主线程的。
那么如果BackgroundWorker是属于主线程的,那么在BackgroundWorker的函数中操作textbox应该没问题吧?因为他们同属一个线程??
到底这个BackgroundWorker有何用呢??
--------------------编程问答-------------------- 我也遇到了这个问题,用BackgroundWorker没有成功,用代理的方式解决的。不过代理也只是使线程访问排序了,多线程的优点一点也体现不出来。
同顶吧 --------------------编程问答-------------------- 倒是 那个好一点呢
--------------------编程问答-------------------- --------------------编程问答-------------------- 2009年的帖子啊。。。
--------------------编程问答-------------------- Invoke。 --------------------编程问答--------------------
补充:.NET技术 , VB.NET