大家都知道,不允许从后台线程更新UI(或不允许?)
我做了一点实验。这是一段代码:var thread = new Thread(() => progressBar1.Increment(50));
thread.IsBackground = true;
thread.Start();
thread.Join();
我将此代码放在一些按钮单击处理程序中。知道吗?我的进度条正在递增...从后台线程。现在我很困惑。我不明白它是如何可能的以及我做错了什么
答案 0 :(得分:7)
我可以从后台线程更新UI,为什么?
最有可能在调试器外部运行时可以这样做。这是因为该保护由Control.CheckForIllegalCrossThreadCalls Property控制。我们来看看reference source
private static bool checkForIllegalCrossThreadCalls = Debugger.IsAttached;
public static bool CheckForIllegalCrossThreadCalls {
get { return checkForIllegalCrossThreadCalls; }
set { checkForIllegalCrossThreadCalls = value; }
}
正如您所看到的,只有在调试时才会默认启用此保护。
如果您在Main
方法中添加以下行(Application.Run
之前)
Control.CheckForIllegalCrossThreadCalls = true;
您的代码将不再有效。
答案 1 :(得分:5)
大家都知道,不允许从后台线程更新UI
不是每个人都知道这一点。但这是事实。从UI线程以外的线程更新大多数UI元素是错误的。
我不明白它是如何可能的
你将一堆沙子倒入汽车的油底壳中。你不应该这样做。那么你怎么可能这样做呢?好像问一个奇怪的问题,不是吗?
汽车是否需要阻止你这样做?不是。当您这样做时,发动机是否需要停止运转?不会。发动机最终会破裂吗?大概。但不一定。
设计汽车的工程师认为你不会做错事,所以他们没有建立任何安全系统来防止或发现这个问题。
我做错了什么?
您正在从后台线程更新UI。不要那样做。但运行时不需要提供防止或检测错误的安全系统。当你做一些你不应该做的事情时,不需要产生错误。如果它想要或不想,它可以自行决定。
或者,以这种方式思考。假设您正在实现运行时,以便它具有您认为具有的属性:运行时将始终检测到错误的跨线程调用并在发生时产生错误。这是一个功能。有人必须设计,编写,测试和维护该代码。代码是什么样的,与它相关的所有成本是什么?
答案 2 :(得分:-1)
就像varocarbas所说,你放入设计师的任何组件都会抛出跨线程异常。
在线程之间访问你需要使用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
}