c# - 在异步方法中设置剪贴板
问题描述
[STAThread]
static void Main(string[] args)
{
DoThing().Wait();
}
static async Task DoThing()
{
Clipboard.SetText("hi");
}
我[STAThread]
首先添加了 bc 我得到了这个错误
ThreadStateException:当前线程必须设置为单线程单元 (STA) 模式,然后才能进行 OLE 调用
但我仍然遇到同样的错误。
剪贴板来自 System.Windows.Forms。
如何从该异步方法设置剪贴板?
解决方案
问题是异步线程是从线程池运行的,它们都是 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
{
// Most usages will require a message pump, which can be
// started by calling Application.Run() at an appropriate point.
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"));
}
请注意,正如 Stephen Cleary 所指出的,通常您需要一个用于 STA 线程的消息泵。如果您只是设置剪贴板文本,您似乎可以摆脱这种情况,但对于任何更复杂的事情,您可能必须在线程中运行消息泵。
运行消息泵的最简单方法是调用Application.Run()
,但您必须自己处理应用程序上下文。
推荐阅读
- azure - 创建的 VNet 未显示在 Azure 的路由表配置中
- python - 如何检测图像的条纹噪声?
- javascript - 如何用两个单独的javascript代码制作两个画布?
- android - sendPasswordResetEmail 现在返回“您的密码已过期或链接已被使用”
- c# - Durable Azure Function Orchestrator 是否会释放计时器锁定?
- ios - 是否可以在不使用 Swift UI 的情况下在 Xcode 11.2 或更高版本中使用 Swift 创建 App Clip?
- asp.net - HTTP 错误 403.14 - Web 服务器配置为不列出此目录的内容。在 .NET 核心 3.1 中
- python - 将带有嵌套列表的字典转换为特定的 pandas df 结构
- java - JPA无法从子类列表中访问父类
- bash - 在 bash 脚本之间共享一个变量