自定义消息框显示时间在用完 WinForms 之前到期
Custom message box show time expiring before it runs out WinForms
我有这个自定义消息框 class :
public class AutoCloseMsb
{
readonly System.Threading.Timer _timeoutTimer;
readonly string _caption;
private AutoCloseMsb(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
MessageBox.Show(text, caption);
}
public static void Show(string text, string caption, int timeout)
{
new AutoCloseMsb(text, caption, timeout);
}
private void OnTimerElapsed(object state)
{
IntPtr mbWnd = FindWindow("#32770", _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WmClose, IntPtr.Zero, IntPtr.Zero);
_timeoutTimer.Dispose();
}
private const int WmClose = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
}
我在几个地方一个接一个地调用它:
AutoCloseMsb.Show("Bot 1 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 2 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 3 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 4 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 5 Turn", "Turns", ThinkTime);
变量 ThinkTime 正在从我实际更改它的资源中获取价值。但是,如果我将 3000 毫秒作为显示时间,它将显示第一个 3 秒,而其他的则不会在此期间显示,它们将在大约 100-200 毫秒内关闭(它们只是显示并立即关闭)为什么这是发生了吗?我应该在显示每个消息框后重置变量的值吗?
如果您单击 MessageBox 中的“确定”按钮,您并没有摆脱 Timer,因此它仍会在消息框关闭后触发。由于标题的 non-uniqueness,OnTimerElapsed 中的事件处理程序将找到一个消息框,然后将其关闭。这会导致随后关闭消息框,因为总有一个 Timer 仍然需要触发。
您的错误的快速修复是移动代码以直接在 MessageBox 而不是 OnTimerElapsed 事件之后删除计时器事件:
private AutoCloseMsb(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
// the next call blocks, until either the user
// or the timer closes the the messagbox
MessageBox.Show(text, caption);
// now we can stop this timer
_timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);
// and dispose it
_timeoutTimer.Dispose();
}
TimerElapsedEvent 仅发出清理可以开始的信号:
private void OnTimerElapsed(object state)
{
Debug.WriteLine("on timer");
IntPtr mbWnd = FindWindow("#32770", _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WmClose, IntPtr.Zero, IntPtr.Zero);
// don't touch the state here, only signal to continue
}
这些更改实现了您想要的并保持代码流清晰。
我有这个自定义消息框 class :
public class AutoCloseMsb
{
readonly System.Threading.Timer _timeoutTimer;
readonly string _caption;
private AutoCloseMsb(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
MessageBox.Show(text, caption);
}
public static void Show(string text, string caption, int timeout)
{
new AutoCloseMsb(text, caption, timeout);
}
private void OnTimerElapsed(object state)
{
IntPtr mbWnd = FindWindow("#32770", _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WmClose, IntPtr.Zero, IntPtr.Zero);
_timeoutTimer.Dispose();
}
private const int WmClose = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
}
我在几个地方一个接一个地调用它:
AutoCloseMsb.Show("Bot 1 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 2 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 3 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 4 Turn", "Turns", ThinkTime);
AutoCloseMsb.Show("Bot 5 Turn", "Turns", ThinkTime);
变量 ThinkTime 正在从我实际更改它的资源中获取价值。但是,如果我将 3000 毫秒作为显示时间,它将显示第一个 3 秒,而其他的则不会在此期间显示,它们将在大约 100-200 毫秒内关闭(它们只是显示并立即关闭)为什么这是发生了吗?我应该在显示每个消息框后重置变量的值吗?
如果您单击 MessageBox 中的“确定”按钮,您并没有摆脱 Timer,因此它仍会在消息框关闭后触发。由于标题的 non-uniqueness,OnTimerElapsed 中的事件处理程序将找到一个消息框,然后将其关闭。这会导致随后关闭消息框,因为总有一个 Timer 仍然需要触发。
您的错误的快速修复是移动代码以直接在 MessageBox 而不是 OnTimerElapsed 事件之后删除计时器事件:
private AutoCloseMsb(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
// the next call blocks, until either the user
// or the timer closes the the messagbox
MessageBox.Show(text, caption);
// now we can stop this timer
_timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);
// and dispose it
_timeoutTimer.Dispose();
}
TimerElapsedEvent 仅发出清理可以开始的信号:
private void OnTimerElapsed(object state)
{
Debug.WriteLine("on timer");
IntPtr mbWnd = FindWindow("#32770", _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WmClose, IntPtr.Zero, IntPtr.Zero);
// don't touch the state here, only signal to continue
}
这些更改实现了您想要的并保持代码流清晰。