几秒钟后closures一个消息框
我有一个Windows窗体应用程序VS2010 C#,我显示一个MessageBox来显示一条消息。
我有一个好的button,但如果他们走开,我想暂停并closures消息框,让5秒后,自动closures消息框。
有自定义MessageBox(从窗体inheritance)或另一个记者窗体,但它将是有趣的没有必要的窗体。
任何关于它的build议或样本?
更新:
对于WPF
在C#中自动closures消息框
自定义MessageBox(使用Forminheritance)
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
Easy to use, custom C# Message Box with a configurable checkbox.
可滚动的MessageBox
C#中的可滚动消息框
例外记者
https://stackoverflow.com/questions/49224/good-crash-reporting-library-in-c-sharp
http://www.codeproject.com/Articles/6895/A-Reusable-Flexible-Error-Reporting-Framework
解:
也许我觉得下面的答案是很好的解决scheme,而不使用表单。
https://stackoverflow.com/a/14522902/206730
https://stackoverflow.com/a/14522952/206730
尝试以下方法:
AutoClosingMessageBox.Show("Text", "Caption", 1000);
其中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); }
更新:如果您希望在超时之前select某些内容时获取底层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); }
又一个更新
我用YesNo
button检查了@ Jack的情况,发现发送WM_CLOSE
消息的方法根本不起作用。
我将在单独的AutoclosingMessageBox库的上下文中提供修复 。 这个库包含重新devise的方法,我相信,可以对某人有用。
它也可以通过NuGet包来获得 :
Install-Package AutoClosingMessageBox
发行说明(v1.0.0.2):
– 新的展示(IWin32Owner)API来支持最stream行的场景(在#1的情况下);
– 新的Factory()API提供对MessageBox的完全控制显示;
使用AppActivate!
如果你不介意混淆你的引用,你可以包含Microsoft.Visualbasic,
并使用这个简短的方法。
显示消息框
(new System.Threading.Thread(CloseIt)).Start(); MessageBox.Show("HI");
CloseItfunction:
public void CloseIt() { System.Threading.Thread.Sleep(2000); Microsoft.VisualBasic.Interaction.AppActivate( System.Diagnostics.Process.GetCurrentProcess().Id); System.Windows.Forms.SendKeys.SendWait(" "); }
现在去洗手!
在WinForms中工作的解决scheme:
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);
基于closures拥有消息框的表单的效果也将closures该框。
Windows窗体控件要求必须在创build它们的同一个线程上访问它们。 使用TaskScheduler.FromCurrentSynchronizationContext()
将确保假设上面的示例代码在UI线程或用户创build的线程上执行。 如果代码在线程池(例如定时器callback)或任务池(例如,使用TaskFactory.StartNew
或Task.Run
使用默认参数创build的任务)上的线程上执行,该示例将无法正常工作。
你可以试试这个:
[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); }
System.Windows.MessageBox.Show()方法有一个重载,它将所有者Window作为第一个参数。 如果我们创build了一个隐形所有者窗口,然后我们在指定时间后closures,那么它的子消息框也会closures。
Window owner = CreateAutoCloseWindow(dialogTimeout); MessageBoxResult result = MessageBox.Show(owner, ...
到现在为止还挺好。 但是,如果UI线程被消息框阻塞,并且UI控件无法从工作线程访问,我们如何closures一个窗口? 答案是 – 通过向所有者窗口句柄发送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; }
这里是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); }
有一个codeproject项目可以在这里提供这个function。
在SO和其他板上的许multithreading之后,不能用正常的MessageBox来完成。
编辑:
我有一个想法是有点呃,是啊..
使用计时器并在出现MessageBox时启动。 如果你的MessageBox只听OKbutton(只有一种可能),然后使用OnTick-Event模拟一个按下SendKeys.Send("{ESC}");
buttonSendKeys.Send("{ESC}");
然后停止计时器。
DMitryG的代码“获取底层MessageBox
的返回值”有一个错误,所以timerResult从来没有实际正确返回( MessageBox.Show
调用返回AFTER OnTimerElapsed
完成)。 我的修复如下:
public class TimedMessageBox { System.Threading.Timer _timeoutTimer; string _caption; DialogResult _result; DialogResult _timerResult; bool timedOut = false; TimedMessageBox(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); if (timedOut) _result = _timerResult; } public static DialogResult Show(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) { return new TimedMessageBox(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(); timedOut = true; } 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); }
RogerB在CodeProject上对这个答案提供了最清晰的解决scheme之一,他在04年就做到了,而且它仍然是“
基本上,你去这里他的项目,并下载CS文件 。 万一链接死了,我在这里有一个备用的要点 。 将CS文件添加到您的项目中,或者将代码复制/粘贴到某处,如果您愿意的话。
那么,你所要做的就是切换
DialogResult result = MessageBox("Text","Title", MessageBoxButtons.CHOICE)
至
DialogResult result = MessageBoxEx("Text","Title", MessageBoxButtons.CHOICE, timer_ms)
你很好走。
user32.dll中有一个名为MessageBoxTimeout()的未公开的API,但它需要Windows XP或更高版本。