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

时间:2015-12-19 18:34:14

标签: c# .net multithreading winforms

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

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

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

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

3 个答案:

答案 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
}