C# 超时后MessageBox的默认对话框结果

C# 超时后MessageBox的默认对话框结果,c#,winforms,messagebox,dialogresult,C#,Winforms,Messagebox,Dialogresult,我需要在C#Framework 3.5中创建一个自定义MessageBox,其中显示一些MesageBox按钮,并返回DialogResult值。如果用户没有反应,则在某个超时时间后,MessageBox应该关闭,并返回null 我遵循DmitryG的回答,做了一些小改动: static DialogResult? dialogResult_ = null; public AutoClosingMessageBox(string text, string caption, int timeou

我需要在C#Framework 3.5中创建一个自定义MessageBox,其中显示一些MesageBox按钮,并返回DialogResult值。如果用户没有反应,则在某个超时时间后,MessageBox应该关闭,并返回null

我遵循DmitryG的回答,做了一些小改动:

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_u值,但是WM_uClose消息在超时时间后不再关闭MessageBox


这是因为MessageBox仍在等待对话框结果吗?如果是,我如何避免它?我希望避免在新线程中启动消息框和终止该线程。

我同意其他评论,即您应该创建自己的消息框表单

这就是说,如果您仍然想使用另一种方法,您应该能够通过向被识别的对话框发送适当的消息来让它工作;e、 g.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
类仅在当前活动窗口上工作,因此我包含了对
setForeGroundIndow()
的调用,以确保键到达正确的窗口


当然,上面的硬代码是Alt-I所需的。如果您想要更通用的解决方案,可以包括一个字典,将
MessageBoxButtons
值映射到关闭该对话框所需的相应
SendKeys
字符串,和/或让调用者提供该信息(强制他们提供实际的
SendKeys
字符串或(更好)让他们传递一个枚举值,指示要使用哪个按钮关闭对话框,然后让您的实现将其映射到相应的字符串。

计时器完成时,您可能应该使用
PostMessage
而不是
SendMessage
。我知道的主要区别是SendMessage等待消息ge待处理,情况就是这样。不幸的是,使用PostMessage没有帮助。我注意到。当向
MessageBox提供
MessageBoxButtons
参数时,Show
消息框窗口右上角的X图标是灰色的。如果不提供MessageBoxButtons参数,则不会发生这种情况。这让我感到困惑相信消息框的内部正在忽略或未接收WM_CLOSE事件窗口上的图标与取消按钮相对应。如果要指定
MessageBox按钮。例如,RetryCancel
,则X按钮处于活动状态,窗口将正确关闭。1-使用表单实现您自己的CustomMessageBox(不要使用MessageBox类)2-尝试侵入MessageBox窗口,以便支持取消…不建议这样做。