web-dev-qa-db-ja.com

ダイアログメッセージボックスがメインフォームの後ろに隠れることがあります

技術者以外のユーザーの中には、アプリケーションのダイアログメッセージボックスがメインフォームの後ろに表示されることがあり、メッセージボックス(表示されない)が閉じられるまでアプリケーションが入力を受け入れないという問題を抱えている人もいます。

アプリケーションはC#で記述されており、メッセージボックスは標準です。たとえば、コードはMessageBox.Show(message、caption)のように単純で、メッセージボックスはメインUIスレッド(つまり、バックグラウンドスレッドではない)で作成できます。アプリケーションはフルスクリーンで実行する必要はありませんが、ユーザーの90%がフルスクリーンで実行しています。

ほとんどの場合((おそらく> 99%)メッセージボックスは正しく表示され、どのように問題が発生するかを確認することはできませんでしたが、問題が発生したときにマシンを見たことがあります。

私が気づいたことの1つは、ダイアログボックスを表示するアプリケーションがある場合、タスクマネージャーを見ると、通常、アプリケーションリストに1つのエントリしか表示されないことです。メッセージボックスが非表示になっている場合は常に、メインアプリケーション用とこのメッセージボックス用の2つのエントリが表示されます。

何が起こったのかがわかれば、問題を解決するのは簡単ですが、技術者以外のユーザーの中には、問題に混乱してコンピュータの電源を切る人もいます。 (そして、リモートデスクトップを使用している人は、それでも問題が解決しない場合はさらに混乱します)。

Vistaで発生し、Windows 2003サーバーのターミナルセッションでも発生すると言われているため、オペレーティングシステムに関連しているとは思いません。

なぜこれが起こっているのか、そしてもっと重要なことに、それを回避するために何かできることがあれば、何か知っていますか?

26
sgmoore

MessageBox.Show()メソッドの一部のオーバーロードは、最初の引数としてIWin32Windowパラメーターを取ります。フォームを最初の引数として渡すと、これが発生するのを防ぐことができます。

22
nukefusion

問題を確認します。これを修正するために行うことは次のとおりです。

  1. 新しいタスクを実行し、メッセージボックスを表示します
  2. タスクの実行中のメインUIスレッドで、DoEventsを実行するループで待機します。このようなもの

2015年12月17日更新。昨日再現された問題。私の場合、リポジトリを作成するには、アプリを最小化します。「待機」ポップアップが表示され(この場合、アイドル時間の後に発生します)、タスクバーでアプリのメインアイコンをクリックします。これによりポップアップが「非表示」になるため、ポップアップを画面に表示することはできません。以下のコードはテストされ、問題を解決します。しかし、私はまだそれが何が/な​​ぜ起こるのか理解していません。

    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;
    }
1
Tom3m

(同じメッセージに対して)常に同じメッセージボックスが同じフォームに表示されますか?

理想的には、問題を自由に、または少なくとも自動的に再現する方法を見つけるようにしてください。これにより、デバッグが容易になり、ユーザーからのフィードバックを数週間待つ必要がなく、将来の変更でバグが修正されることを確認できます。

同じアクションの結果として常に同じメッセージと同じウィンドウ内にあり、MessageBox呼び出しがユーザーの観点からトリガーするのが合理的に簡単であり、UIが比較的標準的である場合は、UIを自動化できます。 AutoIT スクリプトを使用して、問題が発生するまでループで実行します。

および/または、アプリケーションの「デバッグ」ビルドを作成して、一部のユーザー(できれば、最も頻繁に問題が発生していると思われるユーザー)に提供して、 の内容を書き込むことができます。 StackFrame MessageBoxを呼び出す前に、毎回ログファイルなどにオブジェクトを送信します(これを簡単にするために、MessageBoxのラッパーを作成できます)。

次に、ユーザーの1人が問題を抱えている場合は、ログファイルを調べて、ログファイルの出所(ソースコードファイル、行、呼び出しスタックなど)を確認できます。また、これを他のユーザーのログと比較して、MessageBoxが同じ場所からのものかどうか、または異なる場所からのものかどうかを確認することもできます。これにより、問題のあるMessageBoxがどこから呼び出されたのかがわかります。

呼び出しスタックなどを確認するために問題が発生したときにアプリケーションに接続する.Netデバッガーを含む、より簡単な解決策(特にアプリケーションに多数のアセンブリがある場合)があるかもしれませんが、これはネイティブアプリケーションでのみ行いました(OllyDbgを使用)これまでのところ、.Netではありません。他の人はこのアイデアをさらに拡張できるかもしれません...

1

「メッセージボックスcanメインUIスレッドによって作成される」と言いますが、これは、メインUIスレッドによって常に作成されるとは限らないことを意味すると思います。問題は、MessageBox.Showが別のスレッドから呼び出されることがあるようです。

0
MusiGenesis