簡體   English   中英

阻止一個線程上的多個MessageBox而不阻塞

[英]Prevent multiple MessageBoxes on one thread without blocking

我在我的應用程序中注冊了一個錯誤處理程序,當發生未處理的異常時,該錯誤處理程序將顯示一個用戶對話框MessageBox。 它連接到Application.DispatcherUnhandledException事件,因此發生在UI線程上。 現在,我看到了一種情況,每秒定期拋出一次異常,並且不斷彈出新對話框。 我試圖用鎖來防止這種情況發生,但是由於它們都在同一線程上,因此沒有任何效果。 同一線程上的其他睡眠鎖定顯然導致屏幕上單個被阻止的MessageBox。

MessageBox似乎釋放了UI線程,以便其他MessageBox顯示。 在不阻塞線程的情況下如何防止這種情況?

用戶可以選擇繼續或退出應用程序。 當繼續時,下一個排隊的MessageBox應該出現,不應丟棄。 如果一次出現太多消息,則用戶仍然可以決定退出該應用程序。

這里的問題不在於消息框。 當消息框仍處於打開狀態,而又發生另一個異常時,會發生這種情況。 在這種情況下,您的DispatcherUnhandledException處理程序將在同一線程上重新輸入。

但是,用戶尚未對先前的錯誤做出決定,先前的消息框仍在等待他的輸入。 您的調用堆棧如下所示:

=> DispatcherUnhandledExceptionHandler (current)
MessageBox.Show
DispatcherUnhandledExceptionHandler (previous)

顯然,您不能從DispatcherUnhandledExceptionHandler (previous)返回,而無需先從DispatcherUnhandledExceptionHandler (current)返回:您位於同一線程的嵌套調用中。 而且,如果沒有與用戶確認此拳頭,您將無法從DispatcherUnhandledExceptionHandler (current)返回雞蛋。

在堅持您的問題要求的同時,我可以想到解決此問題的一種方法。 它是在另一個線程上顯示消息框,並在等待用戶選擇時阻止主線程的消息循環。 這樣,在您獲得有關當前異常的用戶同意之前,主線程上不會再發生任何異常:

Application.Current.DispatcherUnhandledException += (s, e) =>
{
    this.IsEnabled = false; // disable the main window
    try
    {
        var result = Task.Factory.StartNew(
            () => MessageBox.Show(
                e.Exception.Message, "Continue?", 
                MessageBoxButton.YesNo),
            TaskCreationOptions.LongRunning).Result; // this blocks
        if (result == MessageBoxResult.Yes)
            e.Handled = true;
    }
    finally
    {
        this.IsEnabled = true; // enable the main window
    }
};

從UI經驗的角度來看這很丑陋,但是它為您提供了所需的工作流程。

消息框仍然是在線程上運行的窗口,因此它們必須抽取窗口消息(模態消息循環),以便在需要時重新繪制,移動,處理鍵盤輸入(例如,在控件之間移動的Tab),鼠標輸入。 它們仍將消息分發到同一線程上的其他窗口,以確保擁有它們的窗口被重新繪制。 擁有窗口被禁用,因此輸入消息只會導致播放默認聲音,但是計時器仍會觸發,並且任何發送或發布的消息仍將得到處理。

此類問題的通常根源是您在窗口上附加了System.Windows.Forms.Timer或WPF DispatcherTimer 其他可能性包括使用InvokeBeginInvoke在UI線程上執行某些操作的后台線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM