установить буфер обмена в асинхронном методе - PullRequest
0 голосов
/ 24 июня 2019
[STAThread]
static void Main(string[] args)
{
    DoThing().Wait();
}

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

Я добавил [STAThread], во-первых, я получил эту ошибку

ThreadStateException: текущий поток должен быть установлен в однопотоковый режим (STA), прежде чем OLE-вызовы могут быть сделаны

Но я все еще получаю ту же ошибку.

Буфер обмена из System.Windows.Forms.

Как установить буфер обмена из этого асинхронного метода?

1 Ответ

0 голосов
/ 24 июня 2019

Проблема заключается в том, что асинхронные потоки запускаются из пула потоков, и все они являются потоками 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"));
}
...