为何已使用Invoke,ComboBox仍抛出跨线程操作异常?
解决WinForms跨线程访问ComboBox的异常问题
哦,我一眼就看到问题啦!你的代码里有个很容易忽略的小疏漏——当InvokeRequired为true时,你调用了Invoke去触发UI线程执行方法,但没有在调用后终止当前线程的执行,导致后面的comboBox.SelectedItem = item;依然在非UI线程里跑,这就是为啥还会抛出跨线程异常。
修正后的代码(两种写法任选其一)
写法一:调用Invoke后直接返回
public class ComboBoxAdapter { System.Windows.Forms.ComboBox comboBox; //... public void setSelectedItem( object item ) { if ( comboBox.InvokeRequired ) { comboBox.Invoke( new MethodInvoker( () => setSelectedItem( item ) ) ); return; // 关键:终止当前非UI线程的执行,避免后续代码触发异常 } comboBox.SelectedItem = item; } }
写法二:用else包裹UI线程操作
public class ComboBoxAdapter { System.Windows.Forms.ComboBox comboBox; //... public void setSelectedItem( object item ) { if ( comboBox.InvokeRequired ) { comboBox.Invoke( new MethodInvoker( () => setSelectedItem( item ) ) ); } else { comboBox.SelectedItem = item; } } }
为什么这样能解决问题?
当InvokeRequired为true时,Invoke会把你的委托投递到UI线程的消息队列中,让UI线程去执行setSelectedItem方法。这时候如果原非UI线程不终止执行,就会继续往下走直接操作ComboBox——而WinForms控件不允许非创建线程直接访问,所以就会抛出Cross-thread operation not valid异常。
通过return终止原线程执行,或者用else把赋值逻辑限定在UI线程分支里,就能保证只有创建ComboBox的UI线程才会修改它的SelectedItem属性,自然就不会触发异常了。
内容的提问来源于stack exchange,提问作者Blackbriar
相关产品推荐
相关产品推荐

