1

いくつかの MesageBoxButtons を表示し、DialogResult 値を返す C# Framework 3.5 でカスタム MessageBox を作成する必要があります。ユーザーの反応がない場合、一定のタイムアウト時間が経過すると、MessageBox が閉じて null が返されます。

私は DmitryG's answer hereに従いましたが、マイナーな変更が加えられました:

static DialogResult? dialogResult_ = null;

public AutoClosingMessageBox(string text, string caption, int timeout, MessageBoxButtons msbb)
{
  _caption = caption;
  _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
      null, timeout, System.Threading.Timeout.Infinite);

  dialogResult_ = MessageBox.Show(text, caption, msbb);
}

public static DialogResult? Show(string text, string caption, int timeout, MessageBoxButtons efb)
{
  new AutoClosingMessageBox(text, caption, timeout, efb);
  return dialogResult_;
}

void OnTimerElapsed(object state)
{
  IntPtr mbWnd = FindWindow("#32770", _caption);
  if (mbWnd != IntPtr.Zero)
  {
    SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
    _timeoutTimer.Dispose();
  }

  dialogResult_ = null;
}

    const int WM_CLOSE = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

MessageBox を作成するには、Show 関数を呼び出すだけです。

AutoClosingMessageBox.Show("Show me sth", "capt", 3000, MessageBoxButtons.AbortRetryIgnore);

このアプローチは、ユーザーが MessageBox 内のボタンをクリックすると dialogResult_ 値を返しますが、WM_Close メッセージはタイムアウト時間後に MessageBox を閉じません。

これは、MessageBox がまだ Dialog Result を待っているためですか? はいの場合、どうすれば回避できますか? 新しいスレッドでメッセージ ボックスを開始したり、スレッドを強制終了したりする必要がないようにしたいと考えています。

4

1 に答える 1

1

独自のメッセージボックスフォームを作成する必要があるという他のコメントに同意します。

とはいえ、それでも他のアプローチを使用したい場合は、認識されたダイアログに適切なメッセージを送信することで機能させることができるはずです。たとえば、「無視」の場合は Alt-I です。

あなたが投稿したコードのバージョンは次のとおりです。

class AutoClosingMessageBox
{
    System.Threading.Timer _timeoutTimer;
    string _caption;
    static DialogResult? dialogResult_ = null;

    private AutoClosingMessageBox(string text, string caption, int timeout, MessageBoxButtons msbb)
    {
        _caption = caption;
        _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
            null, timeout, System.Threading.Timeout.Infinite);

        dialogResult_ = MessageBox.Show(text, caption, msbb);
    }

    public static DialogResult? Show(string text, string caption, int timeout, MessageBoxButtons efb)
    {
        new AutoClosingMessageBox(text, caption, timeout, efb);
        return dialogResult_;
    }

    void OnTimerElapsed(object state)
    {
        IntPtr mbWnd = FindWindow("#32770", _caption);
        if (mbWnd != IntPtr.Zero)
        {
            SetForegroundWindow(mbWnd);
            SendKeys.SendWait("%I");
            _timeoutTimer.Dispose();
        }

        dialogResult_ = null;
    }

    [DllImport("user32.dll", SetLastError = true)]
    extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    extern static IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32.dll", SetLastError = true)]
    extern static bool SetForegroundWindow(IntPtr hwnd);

}

このSendKeysクラスは現在アクティブなウィンドウでのみ機能SetForegroundWindow()するため、キーが正しいウィンドウに到達するように への呼び出しを含めました。

もちろん、上記はAlt-I必須です。MessageBoxButtonsより一般的な解決策が必要な場合は、そのダイアログを閉じるのに必要な適切な文字列に値をマップする辞書を含めるSendKeysか、発信者にその情報を提供してもらう (実際のSendKeys文字列を強制的に提供するか、(より適切に) 提供してもらう)ダイアログを閉じるために使用するボタンを示す列挙値を渡し、実装でそれを適切な文字列にマップします。

于 2015-12-09T06:40:34.500 に答える