为什么我们允许从线程池线程修改表单标题?

时间:2019-04-19 09:41:31

标签: c# winforms

下面的等待项在await点尚未完成,并且未捕获UI上下文。这意味着随后的UI修改代码将在另一个线程(在这种情况下为线程池线程)中调用。

private async void Button1_Click(object sender, EventArgs e)
{
    StringBuilder sb = new StringBuilder();
    sb.Append($"{Thread.CurrentThread.ManagedThreadId}, ");

    Task t = Task.Delay(1000);
    await t.ConfigureAwait(false);

    sb.Append($"{Thread.CurrentThread.ManagedThreadId}");

    Text = sb.ToString();
}

上面的代码运行没有问题。运行时没有错误。

问题

为什么允许在非UI线程中修改UI组件? 我的理解有问题吗?

1 个答案:

答案 0 :(得分:3)

默认情况下,除非附加了调试器,否则在Winforms中禁用跨线程检查。可以看到in the initialization of the checkForIllegalCrossThreadCalls field

private static bool checkForIllegalCrossThreadCalls = Debugger.IsAttached;

如果我不得不猜测,我会说这是保持复古兼容性的一种尝试。 .NET 1.1没有跨线程检查(早在我离开时,我一直想知道为什么我的应用程序在几个小时后就会神秘崩溃),它们是与.NET 2.0一起添加的。但这是一个巨大的突破性变化,我想这就是他们选择加入的原因。使用WPF,马上就引入了跨线程检查,因此它们可以为每个人激活。

有鉴于此,我强烈建议您在任何winform项目中手动启用跨线程检查,方法是将此行添加到入口点:

[STAThread]
static void Main()
{
    Control.CheckForIllegalCrossThreadCalls = true;

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}