在异步方法中设置剪贴板

时间:2019-06-24 12:39:05

标签: c# .net ole

[STAThread]
static void Main(string[] args)
{
    DoThing().Wait();
}

static async Task DoThing()
{
    Clipboard.SetText("hi");
}

我首先添加了[STAThread],但出现此错误

  

ThreadStateException:必须先将当前线程设置为单线程单元(STA)模式,然后才能进行OLE调用

但是我仍然遇到相同的错误。

剪贴板来自System.Windows.Forms。

如何通过该异步方法设置剪贴板?

1 个答案:

答案 0 :(得分:0)

问题是异步线程是从线程池运行的,它们都是MTA线程。 Task.Run()还会创建MTA线程。

您将必须显式启动STA线程才能运行代码。这是示例帮助程序类:

public static class STATask
{
    /// <summary>
    /// Similar to Task.Run(), except this creates a task that runs on a thread
    /// in an STA apartment rather than Task's MTA apartment.
    /// </summary>
    /// <typeparam name="TResult">The return type of the task.</typeparam>
    /// <param name="function">The work to execute asynchronously.</param>
    /// <returns>A task object that represents the work queued to execute on an STA thread.</returns>

    public static Task<TResult> Run<TResult>([NotNull] Func<TResult> function)
    {
        var tcs = new TaskCompletionSource<TResult>();

        var thread = new Thread(() =>
        {
            try
            {
                tcs.SetResult(function());
            }

            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();

        return tcs.Task;
    }

    /// <summary>
    /// Similar to Task.Run(), except this creates a task that runs on a thread
    /// in an STA apartment rather than Task's MTA apartment.
    /// </summary>
    /// <param name="action">The work to execute asynchronously.</param>
    /// <returns>A task object that represents the work queued to execute on an STA thread.</returns>

    public static Task Run([NotNull] Action action)
    {
        var tcs = new TaskCompletionSource<object>(); // Return type is irrelevant for an Action.

        var thread = new Thread(() =>
        {
            try
            {
                action();
                tcs.SetResult(null); // Irrelevant.
            }

            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();

        return tcs.Task;
    }
}

然后您可以像这样实现DoThing()

static async Task DoThing()
{
    await STATask.Run(() => Clipboard.SetText("hi"));
}