[英]Inconsistent handling of UI calls from non-UI thread for TabControl
这不是重复项。 WinForms TabControl的这种特殊行为尚未在StackOverflow上进行探讨。
查看以下示例:
我在.NET 4.0中有一个带有两个选项卡的TabControl 。 每个选项卡中都有一个标签 。 当我单击Button时 ,我启动了一个BackgroundWorker ,它现在正在非UI线程上运行。 如果我尝试从tabPage1更改Label ,则由于跨线程调用而收到InvalidOperationException 。 但是修改tabPage2上的Label的第二行运行得很好,没有例外。
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += Bgw_DoWork;
bgw.RunWorkerAsync();
}
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
try
{
label1.Text = "Testing tabPage1"; // This is sitting on tabPage1 - THROWS CROSS THREAD OPERATION
label2.Text = "Testing tabPage2"; // This is sitting on tabPage2 - RUNS FINE
}
catch (Exception ex)
{
throw ex;
}
}
为什么在tabPage2上允许这样做,但在tabPage1上不允许这样做。 在这两种情况下,我们似乎都在从非UI线程修改UI。
这是 Control.Text
属性的设置器:
set
{
// some code omitted
this.WindowText = value;
this.OnTextChanged(EventArgs.Empty);
// some code omitted
}
它只是转发到Control.WindowText
属性。 让我们检查一下:
set
{
if (value == null) value = "";
if (!WindowText.Equals(value)) {
if (IsHandleCreated) {
UnsafeNativeMethods.SetWindowText(new HandleRef(window, Handle), value);
}
else {
if (value.Length == 0) {
text = null;
}
else {
text = value;
}
}
}
}
InvalidOperationException
源自Handle
属性的getter,该方法被调用以获得本机方法调用的HandleRef
实例。
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall, Name));
}
// further code omitted
}
仅当IsHandleCreated
为true
时,才可以访问Handle
属性。 在您的情况下,第二个标签位于尚未显示子项的选项卡项目上,因此第二个标签的IsHandleCreated
为false
。 这意味着,第二个标签的Handle
属性不能在BackgroundWorker
的线程上访问。 而是将文本值仅缓存在控件内的text
字段中。 因此-也不例外。
激活第二个选项卡项目时,将创建Label
的句柄,.NET Framework代码从text
字段中获取缓存的文本值,并将其应用于标签。 这发生在UI线程上,因此再次出现-那里没有异常。
您可以先切换到第二个选项卡项目, 然后按一下按钮。 您将观察到异常。 这是因为在这种情况下,第二个标签的句柄将已经创建。
作为一般的注意-你永远不应该从工作线程访问UI元素,无论观察那些异常与否。 对于与其他线程与UI元素的所有交互,请使用同步: Control.Invoke
或Control.BeginInvoke
, SynchronizationContext
, TaskScheduler
等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.