几秒钟后关闭一个MessageBox

Kiq*_*net 72 c# messagebox winforms

我有一个Windows窗体应用程序VS2010 C#,其中我显示一个MessageBox来显示一条消息.

我有一个好的按钮,但如果他们走开,我想超时并关闭消息框后,让我们说5秒,自动关闭消息框.

有自定义的MessageBox(继承自Form)或其他报告者表单,但有趣的是没有必要的Form.

关于它的任何建议或样品?

更新:

对于WPF
在C#中自动关闭消息框

自定义MessageBox(使用表单继承)
http://www.codeproject.com/Articles/17253/A-Custom-Message-Box

http://www.codeproject.com/Articles/327212/Custom-Message-Box-in-VC

http://tutplusplus.blogspot.com.es/2010/07/c-tutorial-create-your-own-custom.html

http://medmondson2011.wordpress.com/2010/04/07/easy-to-use-custom-c-message-box-with-a-configurable-checkbox/

可滚动MessageBox
C#中的可滚动MessageBox

例外记者
/sf/ask/3445711/

http://www.codeproject.com/Articles/6895/A-Reusable-Flexible-Error-Reporting-Framework

解:

也许我认为以下答案是很好的解决方案,而不使用表格.

/sf/answers/1016603171/
/sf/answers/1016606671/

Dmi*_*ryG 117

尝试以下方法:

AutoClosingMessageBox.Show("Text", "Caption", 1000);
Run Code Online (Sandbox Code Playgroud)

AutoClosingMessageBox类实现如下:

public class AutoClosingMessageBox {
    System.Threading.Timer _timeoutTimer;
    string _caption;
    AutoClosingMessageBox(string text, string caption, int timeout) {
        _caption = caption;
        _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
            null, timeout, System.Threading.Timeout.Infinite);
        using(_timeoutTimer)
            MessageBox.Show(text, caption);
    }
    public static void Show(string text, string caption, int timeout) {
        new AutoClosingMessageBox(text, caption, timeout);
    }
    void OnTimerElapsed(object state) {
        IntPtr mbWnd = FindWindow("#32770", _caption); // lpClassName is #32770 for MessageBox
        if(mbWnd != IntPtr.Zero)
            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        _timeoutTimer.Dispose();
    }
    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);
}
Run Code Online (Sandbox Code Playgroud)

更新: 如果要在超时之前选择某些内容时获取基础MessageBox的返回值,可以使用以下版本的代码:

var userResult = AutoClosingMessageBox.Show("Yes or No?", "Caption", 1000, MessageBoxButtons.YesNo);
if(userResult == System.Windows.Forms.DialogResult.Yes) { 
    // do something
}
...
public class AutoClosingMessageBox {
    System.Threading.Timer _timeoutTimer;
    string _caption;
    DialogResult _result;
    DialogResult _timerResult;
    AutoClosingMessageBox(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) {
        _caption = caption;
        _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
            null, timeout, System.Threading.Timeout.Infinite);
        _timerResult = timerResult;
        using(_timeoutTimer)
            _result = MessageBox.Show(text, caption, buttons);
    }
    public static DialogResult Show(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) {
        return new AutoClosingMessageBox(text, caption, timeout, buttons, timerResult)._result;
    }
    void OnTimerElapsed(object state) {
        IntPtr mbWnd = FindWindow("#32770", _caption); // lpClassName is #32770 for MessageBox
        if(mbWnd != IntPtr.Zero)
            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        _timeoutTimer.Dispose();
        _result = _timerResult;
    }
    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);
}
Run Code Online (Sandbox Code Playgroud)

又一次更新

我用YesNo按钮检查了@ Jack的案例,发现发送WM_CLOSE消息的方法根本不起作用.
我将在单独的AutoclosingMessageBox库的上下文中提供修复.这个库包含重新设计的方法,我相信,对某人有用. 它也可以通过NuGet包获得:

Install-Package AutoClosingMessageBox
Run Code Online (Sandbox Code Playgroud)

发行说明(v1.0.0.2):
- 新的Show(IWin32Owner)API,支持大多数流行的场景(在#1的上下文中);
- 新的Factory()API,提供对MessageBox显示的完全控制;

  • 如果按钮是`System.Windows.Forms.MessageBoxButtons.YesNo`它对我不起作用 (2认同)

BSh*_*arp 24

一个适用于WinForms的解决方案:

var w = new Form() { Size = new Size(0, 0) };
Task.Delay(TimeSpan.FromSeconds(10))
    .ContinueWith((t) => w.Close(), TaskScheduler.FromCurrentSynchronizationContext());

MessageBox.Show(w, message, caption);
Run Code Online (Sandbox Code Playgroud)

基于关闭拥有消息框的表单的效果也将关闭该框.

Windows窗体控件要求必须在创建它们的同一线程上访问它们.TaskScheduler.FromCurrentSynchronizationContext()假设上面的示例代码在UI线程或用户创建的线程上执行,使用将确保.如果代码在线程池(例如计时器回调)或任务池(例如,使用TaskFactory.StartNewTask.Run使用默认参数创建的任务)上执行,则该示例将无法正常工作.

  • 很好的解决方案!补充一点...这在 Winforms 应用程序中运行良好,在为新表单添加 BringToFront 之后,在创建新表单后立即进行。否则,对话框有时会显示在当前活动表单的“后面”,即不会向用户显示。var w = new Form() { Size = new Size(0, 0) }; w.BringToFront(); (2认同)

Fas*_*tAl 16

使用AppActivate!

如果你不介意稍微弄清楚你的参考文献,你可以包括Microsoft.Visualbasic,并使用这个非常简短的方法.

显示MessageBox

    (new System.Threading.Thread(CloseIt)).Start();
    MessageBox.Show("HI");
Run Code Online (Sandbox Code Playgroud)

CloseIt功能:

public void CloseIt()
{
    System.Threading.Thread.Sleep(2000);
    Microsoft.VisualBasic.Interaction.AppActivate( 
         System.Diagnostics.Process.GetCurrentProcess().Id);
    System.Windows.Forms.SendKeys.SendWait(" ");
}
Run Code Online (Sandbox Code Playgroud)

现在去洗手!


Esg*_*sge 11

System.Windows.MessageBox.Show()方法有一个重载,它将所有者Window作为第一个参数.如果我们创建一个不可见的所有者窗口,然后我们在指定的时间后关闭它,它的子消息框也会关闭.

Window owner = CreateAutoCloseWindow(dialogTimeout);
MessageBoxResult result = MessageBox.Show(owner, ...
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但是,如果UI线程被消息框阻止,并且无法从工作线程访问UI控件,我们如何关闭窗口?答案是 - 通过向所有者窗口句柄发送WM_CLOSE窗口消息:

Window CreateAutoCloseWindow(TimeSpan timeout)
{
    Window window = new Window()
    {
        WindowStyle = WindowStyle.None,
        WindowState = System.Windows.WindowState.Maximized,
        Background =  System.Windows.Media.Brushes.Transparent, 
        AllowsTransparency = true,
        ShowInTaskbar = false,
        ShowActivated = true,
        Topmost = true
    };

    window.Show();

    IntPtr handle = new WindowInteropHelper(window).Handle;

    Task.Delay((int)timeout.TotalMilliseconds).ContinueWith(
        t => NativeMethods.SendMessage(handle, 0x10 /*WM_CLOSE*/, IntPtr.Zero, IntPtr.Zero));

    return window;
}
Run Code Online (Sandbox Code Playgroud)

这是SendMessage Windows API方法的导入:

static class NativeMethods
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}
Run Code Online (Sandbox Code Playgroud)

  • Briliant解决方案.在`System.Windows`和`System.Windows.Forms`中有一些命名重叠,花了我一些时间来弄清楚.您将需要以下内容:`System`,`System.Runtime.InteropServices`,`System.Threading.Tasks`,`System.Windows`,`System.Windows.Interop`,`System.Windows.Media` (2认同)

Jen*_*und 10

你可以试试这个:

[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

[DllImport("user32.Dll")]
static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);

private const UInt32 WM_CLOSE = 0x0010;

public void ShowAutoClosingMessageBox(string message, string caption)
{
    var timer = new System.Timers.Timer(5000) { AutoReset = false };
    timer.Elapsed += delegate
    {
        IntPtr hWnd = FindWindowByCaption(IntPtr.Zero, caption);
        if (hWnd.ToInt32() != 0) PostMessage(hWnd, WM_CLOSE, 0, 0);
    };
    timer.Enabled = true;
    MessageBox.Show(message, caption);
}
Run Code Online (Sandbox Code Playgroud)

  • 更好地使用System.Threading.Timer或System.Timers.Timer(如@DmitryG回答)?SendMessage vs PostMessage? (2认同)

Nor*_*ros 9

我知道这个问题已经有 8 年历史了,但是过去和现在都有一个更好的解决方案。它一直都在那里,而且仍然是:MessageBoxTimeout()在 中User32.dll

这是 Microsoft Windows 使用的一个未记录的函数,它完全可以满足您的需求,甚至更多。它也支持不同的语言。

C# 导入:

[DllImport("user32.dll", SetLastError = true)]
public static extern int MessageBoxTimeout(IntPtr hWnd, String lpText, String lpCaption, uint uType, Int16 wLanguageId, Int32 dwMilliseconds);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
Run Code Online (Sandbox Code Playgroud)

如何在 C# 中使用它:

uint uiFlags = /*MB_OK*/ 0x00000000 | /*MB_SETFOREGROUND*/  0x00010000 | /*MB_SYSTEMMODAL*/ 0x00001000 | /*MB_ICONEXCLAMATION*/ 0x00000030;

NativeFunctions.MessageBoxTimeout(NativeFunctions.GetForegroundWindow(), $"Kitty", $"Hello", uiFlags, 0, 5000);
Run Code Online (Sandbox Code Playgroud)

更聪明地工作,而不是更努力地工作。

  • 我来这里寻找这个解决方案,因为 vbscript 总是允许这样做(在那里称为弹出窗口),所以必须有一个底层的本机函数。有点困惑这怎么不是最重要的答案之一。甚至可以使用 WinForms MessageBoxIcon 等枚举,以此作为 uiFlags 值的计算基础。 (2认同)
  • 这个解决方案立即对我有效,并且在一个班级内。我删除了对 _NativeFunctions_ 的引用,因为它全部保留在本地。这似乎比其他答案更容易,因为我不需要下载任何其他软件并且可靠。 (2认同)

kay*_*eck 8

CodeProject 的 RogerB对这个答案提出了最巧妙的解决方案之一,他在 04 年就这样做了,现在仍然很成功

基本上,您到这里访问他的项目并下载 CS 文件。万一该链接失效,我在这里有一个备份要点。将 CS 文件添加到您的项目中,或者如果您愿意,可以将代码复制/粘贴到某处。

然后,你所要做的就是切换

DialogResult result = MessageBox.Show("Text","Title", MessageBoxButtons.CHOICE)
Run Code Online (Sandbox Code Playgroud)

DialogResult result = MessageBoxEx.Show("Text","Title", MessageBoxButtons.CHOICE, timer_ms)
Run Code Online (Sandbox Code Playgroud)

你很高兴去。

  • 您错过了示例中的 .Show 扩展名...应该阅读: DialogResult result = MessageBoxEx.Show("Text","Title", MessageBoxButtons.CHOICE, timer_ms) (2认同)

归档时间:

查看次数:

143719 次

最近记录:

6 年,1 月 前