";当前线程必须设置为单线程单元(STA)“;将字符串复制到剪贴板时出错

本文关键字:字符串 STA 出错 剪贴板 复制 单元 线程 前线 quot 单线程 设置 | 更新日期: 2023-09-27 18:23:58

我已经尝试了C#中如何将数据复制到剪贴板的代码:

Clipboard.SetText("Test!");

我得到了这个错误:

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

我该怎么修?

";当前线程必须设置为单线程单元(STA)“;将字符串复制到剪贴板时出错

如果您无法控制线程是否在STA模式下运行(即测试、其他应用程序的插件,或者只是随机发送调用以在非UI线程上运行的一些代码,并且您不能使用Control.Invoke将其发送回主UI线程),那么您可以在专门配置为STA状态的线程上运行剪贴板访问,这是剪贴板访问所必需的(内部使用OLE,实际需要STA)。

Thread thread = new Thread(() => Clipboard.SetText("Test!"));
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start(); 
thread.Join(); //Wait for the thread to end

确保运行代码的线程标记有[STAThread]属性。对于WinForm和基于控制台的应用程序,通常是Main方法

[STAThread]置于您的主要方法之上:

[STAThread]
static void Main()
{
}

对于WinForms,它通常在生成的Main.cs文件中,如果需要,您可以对其进行编辑(更改时不会重新生成)。对于控制台,您可以定义Main

如果您无法控制线程(即,您正在编写库或主应用程序因某种原因被锁定),您可以在特殊配置的线程(.SetApartmentState(ApartmentState.STA))上运行访问剪贴板的代码,如另一个答案所示。

您只能从STAThread访问剪贴板。

解决此问题的最快方法是将[STAThread]放在Main()方法的顶部,但如果由于任何原因无法做到这一点,则可以使用一个单独的类来创建STAThread集/获取的字符串值。

public static class Clipboard
{
    public static void SetText(string p_Text)
    {
        Thread STAThread = new Thread(
            delegate ()
            {
                // Use a fully qualified name for Clipboard otherwise it
                // will end up calling itself.
                System.Windows.Forms.Clipboard.SetText(p_Text);
            });
        STAThread.SetApartmentState(ApartmentState.STA);
        STAThread.Start();
        STAThread.Join();
    }
    public static string GetText()
    {
        string ReturnValue = string.Empty;
        Thread STAThread = new Thread(
            delegate ()
            {
                // Use a fully qualified name for Clipboard otherwise it
                // will end up calling itself.
                ReturnValue = System.Windows.Forms.Clipboard.GetText();
            });
        STAThread.SetApartmentState(ApartmentState.STA);
        STAThread.Start();
        STAThread.Join();
        return ReturnValue;
    }
}

这个问题已经存在8年了,但许多人仍然需要解决方案。

正如其他人所提到的,剪贴板必须从主线程或[STAThread]调用。

嗯,我每次都使用这种变通方法。也许它可以是一个替代方案。

public static void SetTheClipboard()
{
    Thread t = new Thread(() => {
        Clipboard.SetText("value in clipboard");
    });
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
    t.Join();
    await Task.Run(() => {
        // use the clipboard here in another thread. Also can be used in another thread in another method.
    });
}

剪贴板值是在t线程中创建的。

关键是:线程t单元设置为STA状态。

稍后,您可以在其他线程中随意使用剪贴板值。

希望你能明白。