似乎奥利弗是对的。几次尝试后,我得到了异常,在调试模式下,我肯定得到了它。所以这一切都与时间有关。您还应该检查Matthew wattsons的回答;)
首先,这个例子可以解释我的困惑。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace testCrossThreading
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(ThreadJob).Start();
}
void ThreadJob()
{
//label1.Text = "1";
changeText(label1, "1");
}
void changeText(Label L, String message)
{
L.Text = message;
}
}
}
所以现在我的问题是:如果我在函数“ThreadJob”中取消注释label1.Text = "1";
,那么我会按预期得到一个Cross线程异常。
但如果我留下评论,如示例所示它确实有效。但为什么?
该子函数调用该函数,我不调用任何东西。所以它仍然是子线程,而不是改变标签imo文本的GUI线程。或者我错过了什么?
我会这样写。
void ThreadJob()
{
Action a = () => label1.Text = "1";
this.Invoke(a);
}
答案 0 :(得分:7)
我认为这只是一个时间问题。如果您尝试从非gui线程更新gui元素,则会抛出跨线程异常 。您甚至可以通过调用
来禁用整个跨线程异常Form.CheckForIllegalCrossThreadCalls = false;
但是在异常消失之后,进一步的行为是未定义的,并且可能导致非常微妙的错误。因此,将异常作为代码气味的提示,但请注意,有时异常不会被抛出,即使它应该是。
答案 1 :(得分:2)
我认为你可能有竞争条件,这就是为什么结果会有所不同。
如果您尝试更改当前未显示的控件的Text
属性,则.Net不关心哪个线程更改它。
在代码中,您从构造函数中启动一个线程。实际显示表单的代码可能会或者可能没有在设置属性的线程中的代码执行之前显示它。
当您调用额外函数来设置属性时,时间会发生变化并暴露竞争条件。
您可以通过在Thread.Sleep(100)
的开头添加ThreadJob()
来测试这一点。