2010-08-12 28 views
20

我們的一些非技術用戶遇到問題,我們的應用程序中的對話框MessageBox有時可能顯示在主窗體後面,應用程序直到消息框(它們纔會接受任何輸入看不到)被解僱。Dialog MessageBox有時隱藏在主窗體後面

該應用程序是用C#編寫的,消息框是標準的,例如代碼可以像MessageBox.Show(消息,標題)一樣簡單,並且消息框可以由主UI線程創建(即不是一些後臺線程) 。該應用程序不必全屏運行,但我們90%的用戶確實全屏運行。

大多數時候((說不定> 99%)的消息框顯示正確,我從來沒有成功地看到它是如何去錯了,但我已經看到了一臺機器,當它出現了偏差。

有一件事我我們注意到,如果你有一個應用程序顯示一個對話框,那麼當你看到你的任務管理器時,你通常只會在應用程序列表中看到一個條目,當消息框被隱藏時,你會看到兩個條目,一個用於main應用程序和此消息框的另一個條目

一旦知道發生了什麼,就可以很容易地解決問題,但是我們的一些非技術用戶對此感到困惑,並最終關閉了i電腦。 (那些使用遠程桌面的人在解決問題時更加困惑)。

我不認爲它與操作系統有關,因爲我已經看到它發生在Vista中,並且被告知它也發生在Windows 2003服務器上的終端會話中。

是否有任何事情知道爲什麼會發生這種情況,更重要的是,如果能做些什麼來避免它呢?

+0

我遇到了與WPF相同的問題。有些東西可能會觸發對話框與主窗口之間的關係,即使沒有指定,通常也會存在被打破的關係。提供一個窗口作爲第一個參數解決了問題。爲了重新創建它,我在VS調試器中運行了應用程序。調試器處於活動狀態往往會破壞關係。你可以知道問題已經發生,因爲對話框將在任務欄上獲得它自己的條目。 – denver 2015-08-11 20:54:21

回答

18

MessageBox.Show()方法的一些過載以IWin32Window參數作爲第一個參數。如果您將表單作爲第一個參數傳遞,應該防止發生這種情況。

+0

+1用於指定父窗口。 OP的問題很可能意味着消息框有一個空的父(即桌面窗口),有時這個窗口在後臺結束。 – casablanca 2010-08-12 15:24:01

+0

有什麼方法可以確定消息框的父級(在運行時和客戶機器上)? – sgmoore 2010-08-12 17:16:19

+2

http://www.catch22.net/software/winspy可以告訴你。 – 2010-08-12 17:37:21

0

你說「messageboxes 可以由主UI線程創建」,我想這意味着它們並不總是由主UI線程創建的。你的問題聽起來像MessageBox.Show偶爾從另一個線程調用。

+0

不,我的意思是,雖然它發生的一些時間是由後臺線程創建的消息框,但它也出現在由主UI線程明確創建的消息框中。 – sgmoore 2010-08-12 12:28:48

+0

你是否在你的表單做任何時髦?像PInvoking SetWindowPos或類似的東西? – MusiGenesis 2010-08-12 12:41:08

+0

否。在顯示初始屏幕並且程序初始化時,實際顯示mainform之前,唯一通常的事情是將ShowInTaskbar設置爲false。 ShowInTaskbar在Mainform Load事件結束時設置爲true。 – sgmoore 2010-08-12 13:19:47

1

它是否始終是相同的消息框(相同的消息?)來到相同的形式?

理想情況下,您應該嘗試找到某種方法隨意或至少自動地重現問題。這將使您的調試變得更加容易,然後您可以確保您的未來更改能夠修復錯誤,而不必等待幾個星期才能獲得用戶的反饋。

如果它始終是相同的消息,並且在相同的窗口中,由於相同的操作,並且如果MessageBox調用可以從用戶的角度合理輕鬆觸發,並且您的UI相對標準,那麼您可以使用AutoIT腳本自動執行UI,並讓它在循環中運行,直到問題發生。您可以創建一個「調試」構建您的應用程序,您可以將它提供給某些用戶(最好是那些似乎經常遇到問題的用戶),它會將內容寫入StackFrame在每次調用MessageBox之前每次都要將日誌文件或類似對象寫入日誌文件(您可以在MessageBox周圍創建一個包裝以使其更容易)。然後,當你的某個用戶遇到問題時,你可以查看日誌文件並查看它來自哪裏(源代碼文件,行,調用堆棧等)。您還可以將其與其他用戶的日誌進行比較,並查看每次MessageBox是否來自同一位置或是否有所不同。 這會告訴你哪裏有問題的MessageBox從哪裏調用。

可能有更簡單的解決方案(特別是如果您的應用程序有很多程序集)涉及一些.Net調試程序,當問題發生時您將附加到您的應用程序以查看調用堆棧等,但我只做了這與原生應用程序(使用OllyDbg)到目前爲止,而不是.Net。其他人可能可以進一步擴大這個想法...

+0

它並不總是相同的消息,並且可以從程序的不同部分創建消息框。但是,我最後一次看到這條消息時,從消息中知道它是從哪裏來的。 試圖自動化它的問題是我認爲外部因素到位。當第一次報告時,我認爲這可能是由於用戶最小化了應用程序在另一個程序上工作以及在應用程序被最小化時創建的消息框引起的。但如果我這樣做,每當我切換回我的應用程序時,消息框也顯示在前面。 – sgmoore 2010-08-12 16:43:38

+0

如果你已經排除了線程假設,我想你可能需要排除儘可能多的常見嫌疑人。您是否嘗試在原始機器(或VM)中運行您的應用程序?不確定它在你的環境中有多實用,但是,儘管很少見,但實用程序或其他軟件試圖在某個時刻竊取焦點或導致窗口發生一些奇怪的事情並非不可能。另外,它看起來像你從來沒有親眼目睹錯誤。 – 2010-08-12 17:33:06

+0

另外,如果您的用戶是內部員工,並且已準備好接受它,您可以記錄他們的屏幕,以便您可以在下次發生問題時查看他們給您打電話時發生的情況。也就是說,他們觀察到的事實本身可能會引入一些奇怪的安慰劑效應(例如,如果用戶在您的應用程序處理某些內容時訪問網站,並且他們不知道您可以觀看該錄音)。 – 2010-08-12 17:34:41

1

確認問題。我們要解決的問題如下: 1.運行新任務並顯示消息框 2.在任務仍在運行的主UI線程中 - 等待執行DoEvents的循環。像這樣的東西

更新2015-12-17。 轉載問題yestarday。以我的情況回購 - 最小化應用程序,「等待」彈出窗口(在我們的情況下,它發生在空閒時間後),然後在任務欄中單擊主應用程序圖標。這會「隱藏」彈出窗口,因此無法將其顯示在屏幕上。下面的代碼經過測試並解決了這個問題。但我仍然不明白爲什麼會發生。

private static DialogResult ShowMessageBox(
     string message, 
     string caption, 
     MessageBoxButtons buttons, 
     MessageBoxIcon icon) 
    { 

     var showMessageBoxTask = new Task<DialogResult>(() => 
     { 
      var form = new Form() {TopMost = true}; 

      var result = MessageBox.Show(
       form, 
       PrepareMessage(message), 
       caption, 
       buttons, 
       icon); 

      form.Dispose(); 

      return result; 
     }); 

     showMessageBoxTask.Start(); 

     while (!showMessageBoxTask.IsCompleted && !showMessageBoxTask.IsFaulted) 
     { 
      Application.DoEvents(); 
     } 

     return showMessageBoxTask.Result; 
    }