我可以从后台线程更新UI,为什么?

大家都知道,不允许从后台线程更新UI(或不是?)

我做了一个小实验。 这是一段代码:

var thread = new Thread(() => progressBar1.Increment(50)); thread.IsBackground = true; thread.Start(); thread.Join(); 

我将此代码放在一些按钮单击处理程序中。 知道吗? 我的进度条正在递增…从后台线程。 现在我很困惑。 我不明白这是怎么可能的,我做错了什么

我可以从后台线程更新UI,为什么?

最有可能的是,当你在调试器外面运行时,你可以这样做。 这是因为该保护由Control.CheckForIllegalCrossThreadCalls属性控制。 我们来看看参考源

 private static bool checkForIllegalCrossThreadCalls = Debugger.IsAttached; public static bool CheckForIllegalCrossThreadCalls { get { return checkForIllegalCrossThreadCalls; } set { checkForIllegalCrossThreadCalls = value; } } 

如您所见,只有在调试时才会默认启用此保护。

如果在Main方法中添加以下行(在Application.Run之前)

 Control.CheckForIllegalCrossThreadCalls = true; 

你的代码将不再有效。

大家都知道,不允许从后台线程更新UI

不是每个人都知道。 但这是事实。 从UI线程以外的线程更新大多数UI元素是错误的。

我不明白它是怎么可能的

你把一堆沙子倒进汽车的油底壳里。 你不应该这样做。 那么你怎么可能这样做呢? 好像问一个奇怪的问题,不是吗?

汽车是否需要阻止你这样做? 不是。当您这样做时,发动机是否需要停止运转? 不会。发动机最终会破裂吗? 大概。 但不一定。

设计你的汽车的工程师认为你不会做错事,所以他们没有建立任何安全系统来防止或发现这个问题。

我究竟做错了什么?

您正在从后台线程更新UI。 不要那样做。 但运行时不需要提供防止或检测错误的安全系统。 当你做一些你不应该做的事情时,不需要产生错误。 如果它想要或不想要,它可以这样做。

或者,这样想一想。 假设您正在实现运行时,以便它具有您认为具有的属性:运行时将始终检测到错误的跨线程调用并在发生时产生错误。 这是一个function。 有人必须设计,编写,测试和维护该代码。 代码是什么样的,与之相关的所有成本是多少?

就像varocarbas所说,你放入设计器的任何组件都会抛出Cross threadexception。

要在线程之间访问你需要使用invke,beginInvoke。

试着跑

 BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += (s1,e1) => { textBoxt1.Text = "foo"; // Exception here } bw.RunWorkerCompleted += (1s, e1) => { textBoxt1.Text = "foo"; // No exception here off UI thread } bw.RunWorkerAsync(); 

而是替换

 bw.DoWork += (s1,e1) => { this.Invoke((MethodInvoker) delegate { textBoxt1.Text = message; }); // No Exception now }