[英]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.