在计时器中使用 QueueUserWorkItem 时出现 ThreadStateException

发布于 2024-09-04 18:28:37 字数 654 浏览 4 评论 0原文

我的 WinForms 应用程序中有一个 ThreadStateException。

重现步骤:

  • 创建简单的 winforms 应用程序
  • 添加计时器
  • 在单击事件中,执行以下操作:

    timer1.Interval = 1000;
    定时器1.Tick += 定时器1_Tick;
    定时器1.Start();
    

    voidtimer1_Tick(对象发送者,EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(委托
        {
            字符串集合路径=
                新的 StringCollection { @"c:\my.txt", @"c:\my.png" };
            Clipboard.SetFileDropList(路径);
        });
    }
    

告诉我:

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

但main已经有了[STAThread]属性。

怎么解决呢?

I have a ThreadStateException in my WinForms application.

Step to reproduce:

  • Create simple winforms app
  • Add a Timer
  • In click event, do :

    timer1.Interval = 1000;
    timer1.Tick += timer1_Tick;
    timer1.Start();
    

    with

    void timer1_Tick(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(delegate
        {
            StringCollection paths =
                new StringCollection { @"c:\my.txt", @"c:\my.png" };
            Clipboard.SetFileDropList(paths);
        });
    }
    

The exception tells me:

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.

But the main has already the [STAThread] attribute.

How to solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久夏青 2024-09-11 18:28:37

Thread.SetApartmentState() 方法在这里很重要。剪贴板是一个 COM 对象,它不是线程安全的。有许多 Windows 功能具有类似的行为,拖放和 OpenFileDialog 等 shell 对话框是其他示例。

您无法设置线程池线程的单元状态,它始终是 MTA(多线程单元)。您可以在常规线程上,但额外的 STA 要求是您还需要泵送消息循环 (Application.Run)。这又给你带来了完全相同的问题:你不能阻塞或花费很长时间来执行代码。

简单的解决方案是在线程上执行需要很长时间执行的操作。并从 UI 线程进行剪贴板调用。使用Control.BeginInvoke() 或更好的BackgroundWorker.RunWorkerCompleted。

The Thread.SetApartmentState() method is important here. The Clipboard is a COM object, it is not thread-safe. There are many Windows features that behave like this, Drag+Drop and the shell dialogs like OpenFileDialog are other examples.

You cannot set the apartment state of a threadpool thread, it is always MTA (Multi-threaded apartment). You can on a regular Thread but an additional STA requirement is that you also pump a message loop (Application.Run). Which gives you the exact same problem back: you cannot block or take a long time to execute code.

The simple solution is to do whatever takes a long time to execute on a thread. And make the Clipboard call from the UI thread. Use Control.BeginInvoke() or, better, BackgroundWorker.RunWorkerCompleted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文