最近做個小項目,用到一個小功能:背景線程定時查詢資料庫,不符合條件的記錄彈出消息提醒(在視窗最前面),并且過幾秒鐘再自動關閉彈出的視窗。
是以從網上找來資料,如下:
WinForm 下實作一個自動關閉的MessageBox
Author: eaglet
WinForm 下我們可以調用MessageBox.Show 來顯示一個消息對話框,提示使用者确認等操作。在有些應用中我們需要通過程式來自動關閉這個消息對話框而不是由使用者點選确認按鈕來關閉。然而.Net framework 沒有為我們提供自動關閉MessageBox 的方法,要實作這個功能,我們需要使用Window API 來完成。
首先我們需要找到這個消息對話框的視窗句柄,一個比較簡單的方法就是用 FindWindow API 來查找對應的窗體句柄。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
[DllImport("user32.dll", SetLastError = true)]
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
這個API調用可以通過視窗的類名或者視窗标題的名字來查找視窗句柄。
接下來我們還需要找到一個 API 來關閉對話框,這裡我使用 EndDialog
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
[DllImport("user32.dll")]
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
static extern bool EndDialog(IntPtr hDlg, out IntPtr nResult);
有了這兩個API函數,我們就可以來關閉消息對話框了。思路是在調用MessageBox.Show 前啟動一個背景工作線程,這個工作線程等待一定時間後開始查找消息對話框的視窗句柄,找到後調用EndDialog API 函數關閉這個消息對話框。不過這個方法有個問題,就是如果同時又多個同名的消息對話框(可能不一定是這個應用的),這樣做可能會關錯視窗,如何解決這個問題,我還沒有想出比較好的方法,如果大家有更好的方法解決這個問題,不妨一起讨論讨論。
我根據這個思路編寫了延時關閉消息對話框的函數
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
public void ShowMessageBoxTimeout(string text, string caption,
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
MessageBoxButtons buttons, int timeout)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CloseMessageBox),
new CloseState(caption, timeout));
MessageBox.Show(text, caption,buttons);
}
這個函數中timeout 參數機關是毫秒,其他參數和MessageBox.Show的參數含義是一樣的,這裡不再詳細說明。
這個函數中首先利用線程池調用一個工作線程 CloseMessageBox ,并将對話框的标題和延時時間通過CloseState這個類傳遞給CloseMessageBox函數。
CloseState 的定義如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
private class CloseState
{
private int _Timeout;
/// <summary>
/// In millisecond
/// </summary>
public int Timeout
{
get
{
return _Timeout;
}
}
private string _Caption;
/// <summary>
/// Caption of dialog
/// </summary>
public string Caption
{
get
{
return _Caption;
}
}
public CloseState(string caption, int timeout)
{
_Timeout = timeout;
_Caption = caption;
}
}
最後就是CloseMessageBox函數了,直接看代碼吧
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLl52bO9CXzJ3b0F2YpRmbJdmbp5WasRXdP9CXzV2Zh1WSvwVbvNmLzd2bsJmbj5yd3d3Lc9CX6MHc0RHaiojIsJye.gif)
private void CloseMessageBox(object state)
{
CloseState closeState = state as CloseState;
Thread.Sleep(closeState.Timeout);
IntPtr dlg = FindWindow(null, closeState.Caption);
if (dlg != IntPtr.Zero)
{
IntPtr result;
EndDialog(dlg, out result);
}
}
出處:http://www.cnblogs.com/XGLSummer/archive/2012/09/06/2673334.html ============================================================================================= 發現上面的代碼是可以,但彈出的視窗沒有在最前面,是以還需要繼續找資料。
在螢幕的最前面彈一個消息框
有人要說了,彈一個ShowDialog不就完了嗎?!或者MessageBox.Show("saaaaa");就可以達到目的。
但你要看到下面的情況,你就不這樣說了。
我在C#中建立了一個Excel,每當我編輯一個值的時候,都會用C#代碼判斷這些值是否是有效的,當無效進就提醒他們。我用的就是MessageBox.Show("aaaaaaa");
但它不一定彈在最前面,因為它是C#的代碼,故當Excel在最前面時,那個消息框是不能顯示在最頭面的。
用以下方法可以解決此問題:
MessageBox.Show("要彈的資訊。", "資訊", MessageBoxButtons.OK, MessageBoxIcon.Information,MessageBoxDefaultButton.Button1, essageBoxOptions.DefaultDesktopOnly);
呵呵,雖然還是那個MessageBox.Show,但很多人都不知道呀。大家可以試試。
出處:http://www.cnblogs.com/pnljs/archive/2012/09/19/2694182.html ======================================================================================================== 使用上面的代碼,可以實作彈出視窗在最上面,但是結合第一段的代碼,無法正常關閉,直接報錯了。說明調用的static extern bool EndDialog(IntPtr hDlg, out IntPtr nResult);方法不能正常關閉視窗,那麼咱們再重新找個可以關閉視窗的API函數把。在網上找到如下代碼:
public const int WM_CLOSE = 0x10;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageA")]
public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
private void button1_Click(object sender, System.EventArgs e)
{
IntPtr hwnd_win;
hwnd_win = FindWindow(null, "要找的窗體名");
SendMessage(hwnd_win, WM_CLOSE, 0, 0);
}
查找視窗函數:
//查找窗體
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
static void Main()
{
//@Form1根據窗體的Text文本值獲得窗體
int WINDOW_HANDLER = FindWindow(null, @"Form1");
}
出處:http://bbs.csdn.net/topics/340065537/ ======================================================================================= 通過以上幾步,我們現在可以正常的實作了我們文章開頭提到的功能了。