static async Task Foo() {
while (true) {
await Task.Delay(1000);
Console.WriteLine("PRINT");
}
}
static void Main(string[] args) {
var strip = new MenuStrip();
Foo();
Console.ReadKey();
}
此代码示例演示了奇怪的行为:实例化后MenuStrip
,该方法Foo
在调用时被阻塞Task.Delay
。如果您不创建实例MenuStrip
,那么一切都会正常运行 - 每隔一秒就会向控制台打印一条消息PRINT
。为什么会这样?
目标框架:.NET 6.0
目标操作系统:Windows
MenuStrip
,作为 Windows 窗体组件,在其构造函数中自动设置 Windows 窗体同步上下文。WindowsFormsSynchronizationContext.AutoInstall
您可以通过将属性设置为 false来避免这种情况:但是,作为一项规则,组件出于某种原因需要此上下文,因此在一般情况下,简单地设置 false 是不可取的。相反,您可以将 Foo 方法调用显式移出同步上下文:
此外,如果您正在创建任何 Windows 窗体控件,您很可能需要一个主循环。运行它也可以解决问题:
如果您还需要在控制台中按下某个键时关闭应用程序,则必须在另一个线程中读取,并通过应用程序上下文将其关闭:
这就是代码的工作方式:
添加
.ConfigureAwait(false)
.一个普通的控制台应用程序是没有同步上下文的,但是这个程序实际上是一个 WinForms 应用程序,所以它有一个同步上下文。因此,必须考虑它的存在。
该属性
[STAThread]
很可能仅在使用 COM 对象或在内部使用它们的组件时才需要。该组件
NotifyIcon
不在表单上,而是在托盘中,据我所知,它不直接使用表单的消息流。因此,它的行为不同于标准的窗口控件。