小言_互联网的博客

Thread\Threading.Timer\Task中ShowDialog()方法报错:“在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式”

378人阅读  评论(0)

在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。

出错环境:

1、在Thread线程中,调用ShowDialog()方法

2、在线程定时器中,调用ShowDialog()方法

3、在Task任务中调用ShowDialog()方法

 

出错异常:

当执行到.ShowDialog()方法的时候,就会出现如下错误提示:“在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式,请确保您的Main函数带有STAThreadAttribute标记。”

 

出错原因:

1、首先先确认一下程序主入口是否有STAThreadAttribute标记,如果没有请加上[STAThread]查看问题是否解决

2、由于该操作在新创建的线程中执行,是不能访问UI的,也就是直接调用ShowDialog()方法确实是有问题的。非UI线程不能打开窗口

 

解决方案:

1、Thread 线程

通过将线程的 ApartmentState 属性设置为ApartmentState 枚举值之一,可以控制所创建的单元的类型。

其中:

STA:Thread 将创建并进入一个单线程单元;

MTA:Thread 将创建并进入一个多线程单元;

Unknown:尚未设置 ApartmentState 属性。

代码如下:


  
  1. Thread th = new Thread(()=> new Form1().ShowDialog());
  2. th.SetApartmentState(ApartmentState.STA);
  3. th.Start();

这是网上常用的做法

2、System.Threading.Timer 线程定时器

见下文!!

3、Task 任务

Task封装的是任务,是工作内容,不是线程。一个Task可能在任何线程上执行,所以Task不会提供线程属性,也不该在异步方法中使用Thread类,更不应该在Task里面修改线程的ApartmentState属性,因为这个线程可能会执行其他的Task。亦或者说STA 线程不能是线程池线程!! 见下文!!


因此!!大招在此!!!

👉多线程访问界面应该使用Control.Invoke委托让UI线程自己做👈

this.Invoke(some delegate);//同步
or
this.BeginInvoke(some delegate);//异步

代码如下:


  
  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3. Func< string> func = OFD;
  4. Task task = new Task(() =>
  5. {
  6. string res = ( string) this.Invoke(func); //同步!让UI线程自己做
  7. });
  8. task.Start();
  9. }
  10. private string OFD()
  11. {
  12. OpenFileDialog dlg = new OpenFileDialog();
  13. if (dlg.ShowDialog() == DialogResult.OK)
  14. {
  15. string path = dlg.FileName;
  16. return path;
  17. }
  18. return null;
  19. }

 


转载:https://blog.csdn.net/qq_48705696/article/details/117380348
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场