2013-06-06 217 views
0

你能解釋爲什麼會發生這種情況嗎?以下是重現異常的步驟:Win32Exception - 錯誤創建窗口句柄?

  1. 在表單上拖放文本框。在窗體上添加任何其他可對焦的控件,例如按鈕。
  2. 添加2個事件處理程序爲文本框如下:

    private void textBox_GotFocus(object sender, EventArgs e){ 
        ((TextBox)sender).HideSelection = false; //<-- exception highlighted at here. 
    } 
    
    private void textBox_LostFocus(object sender, EventArgs e){ 
        ((TextBox)sender).HideSelection = true; 
    } 
    
  3. 運行形式和文本框中第一次點擊,然後點擊按鈕,然後點擊文本框再次,異常會拋出: 「Win32Exception - 創建窗口句柄時出錯」。

該代碼僅僅是爲了使得當文本框聚焦並失去焦點時相應地改變HideSelection。

UPDATE

我不知道爲什麼是如此不穩定,我創造了另一個項目,現在的問題是不同的,沒有例外,但無限循環,這使得文本框中閃爍,形式似乎並不爲了響應,CPU使用率消耗高達17-20%。最後一個演示仍然打開,該演示仍然會引發Win32Exception。根本不是線索。現在兩個項目的代碼是一樣的,但問題不同。

+0

正在使用GotFocus和LostFocus事件的第三方文本框控件? –

+0

@Jeremy Thopmson這些事件確實存在於TextBox控件中,只是在設計器中不存在;-) – EtherealMonkey

+0

@ King King,在顯示錶單之前''TextBox'被重繪多次。這是我嘗試診斷問題時首先解決的問題 - 我在Form_Shown()事件處理程序中設置了一個bool標誌,然後用它來防止啓動時的無限循環(通過將代碼包裝在其中)。在啓動後經過無限循環後,我試圖解決您的問題,但是JeffRSon擊敗了我! – EtherealMonkey

回答

2

嗯,有幾件事情要注意。

首先,HideSelection不隱藏或取消隱藏選擇。它指定了當控件失去焦點時選擇是否被隱藏(或不)。所以當TextBox成爲焦點時,改變它是毫無意義的。

你在做什麼LostFocus是默認的,順便說一句。我猜,爲什麼在Windows API中存在GotFocus異常。當HideSelection檢查焦點更改事件時,無論TextBox是否具有焦點或試圖隱藏未顯示的選擇,可能會出現一些未定義的狀態。 編輯:這不是第一手的Windows API,而是框架。它試圖在HideSelection 的setter中「重新創建句柄」(如果它被更改的話)(不知道爲什麼 - 將不得不分析源代碼)並且似乎失敗(不知道爲什麼)。 Edit2:最後在Win32 DestroyWindow中存在一些問題 - 這會導致跳過創建新窗口。也許是因爲舊焦點在焦點變化事件中「正在使用」?有趣的是,只要發生異常(對我來說),就會觸發LostFocus事件,緊接着是GotFocus,它引發另一個異常a.s.o.從而阻止了GUI。 HideSelection的兩項任務都會拋出異常。

此外,當您單擊TextBox時,將自動取消選擇任何選擇。但是,這並不是原因,因爲如果通過按Tab(其正常行爲是恢復焦點)更改焦點,則會引發異常。但它可能是相關的(國家問題)。

如果你真的想恢復的選擇,你可以做這樣的:

int selStart; 
int selLen; 
void textBox1_LostFocus(object sender, EventArgs e) 
{ 
    selStart = textBox1.SelectionStart; 
    selLen = textBox1.SelectionLength; 
} 
void textBox1_GotFocus(object sender, EventArgs e) 
{ 
    BeginInvoke((Action)(() => 
    { 
     textBox1.SelectionStart = selStart; 
     textBox1.SelectionLength = selLen; 
    })); 
} 
+1

Arrrggg,我不能在這裏得到任何代表...總是有人比我更快。恭喜,今天就是你;-)! – EtherealMonkey

+0

謝謝,我沒有注意到HideSelection的實際含義:) –

0

不能重現這個工作對我來說:

private void textBox1_Leave(object sender, EventArgs e) 
{ 
    ((TextBox)sender).HideSelection = false; 
} 

private void textBox1_Enter(object sender, EventArgs e) 
{ 
    ((TextBox)sender).HideSelection = true; 
} 
+1

你確定嗎?我試過一個只有2個控件的新項目:文本框和一個按鈕。甚至無法正常運行。文本框被重複閃爍,這裏似乎有一些不確定的循環,CPU使用率約爲17%。最後一個演示是在窗體上有大約6個控件時創建的。 –

2

我瑞普此崩潰。通過在事件處理程序中設置斷點,您可以很容易地看到它出錯,請注意在程序炸彈爆炸之前它們會一遍又一遍地重複。解釋有點冗長,我會先給出簡短的版本。 LostFocus事件的MSDN documentation給出了嚴重警告(注意和警告),指出這是一個危險的低級事件。出於這個原因,這些事件也隱藏在「屬性」窗口中。通過使用Enter和Leave事件來解決您的問題。

長版本:TextBox.HideSelection屬性比較特殊。它與指定本機Windows控件上的某些屬性的方式有關。這些控件是用CreateWindowEx() winapi函數創建的,它需要一個dwExStyle和dwStyle參數,這些參數指定窗口的樣式選項。 HideSelection屬性就是這樣一個樣式標誌ES_NOHIDESEL。

這就出現了一個問題,當你想更改的屬性。很難,因爲只能在創建本地控件時指定它。 Winforms做了一些非常英雄的事來處理這個限制,它破壞了本地控制並重新創建它。

這可以有相當有趣的副作用,說得溫和。大多數是不可觀察的,但例如,您可以看到屏幕上的窗口被破壞並重新創建。這就是它閃爍的原因。代碼的核心問題是不可避免的,因爲本地窗口正在被破壞,它也失去了焦點。因此,在獲得GotFocus事件後,LostFocus事件立即啓動。哪個做了不幸的事情,再次更改了HideSelection屬性。這迫使Winforms再次重新創建本地控件。

當您的GotFocus事件處理程序再次運行以用於新的本地控件時,它會一遍又一遍地重複。當Windows停止並且不允許創建任何更多的本地窗口時,這最終會結束,它會在一段時間後在10,000個控件上拉動插件。其中生成「錯誤創建窗口句柄」異常。

輸入和離開事件應始終用於聚焦事件,它們僅在用戶實際移動焦點時觸發,並且在因其他原因(如此類事件)發生時不會觸發。同樣值得注意的是,像你一樣改變HideSelection屬性沒有任何意義,當TextBox沒有焦點時,該屬性只有一個影響。選擇在焦點時從不隱藏。因此,在這裏正確的解決方法是刪除這些事件處理程序,並只需在屬性窗口中將HideSelection屬性設置爲True。默認值。

+0

哇謝謝,你的解釋對我有很大的幫助,事實上我之前並沒有注意到HideSelection的實際含義。謝謝! –