以父窗体为中心的MessageBox

是否有一种简单的方法,以.net 2.0中的父窗体为中心的MessageBox

从Joel Spolsky的博客评论:

一个消息框始终居中在屏幕上。 你可以提供一个所有者,但这只是为了Z-顺序,而不是集中。 唯一的方法是使用Win32钩子并自己居中。 你可以find代码,如果你在网上search它。

只需编写自己的消息框类并添加定中心function就容易多了。 然后,您还可以添加默认字幕,不要再显示 – checkbox,并使其无模式。

“Win32挂钩”可能是指使用SetWindowsHookEx ,如本例所示。

我真的需要在C#中find中心MessageBox C#

这是一个很好的格式化版本

 using System; using System.Windows.Forms; using System.Text; using System.Drawing; using System.Runtime.InteropServices; public class MessageBoxEx { private static IWin32Window _owner; private static HookProc _hookProc; private static IntPtr _hHook; public static DialogResult Show(string text) { Initialize(); return MessageBox.Show(text); } public static DialogResult Show(string text, string caption) { Initialize(); return MessageBox.Show(text, caption); } public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) { Initialize(); return MessageBox.Show(text, caption, buttons); } public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { Initialize(); return MessageBox.Show(text, caption, buttons, icon); } public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton) { Initialize(); return MessageBox.Show(text, caption, buttons, icon, defButton); } public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton, MessageBoxOptions options) { Initialize(); return MessageBox.Show(text, caption, buttons, icon, defButton, options); } public static DialogResult Show(IWin32Window owner, string text) { _owner = owner; Initialize(); return MessageBox.Show(owner, text); } public static DialogResult Show(IWin32Window owner, string text, string caption) { _owner = owner; Initialize(); return MessageBox.Show(owner, text, caption); } public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons) { _owner = owner; Initialize(); return MessageBox.Show(owner, text, caption, buttons); } public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { _owner = owner; Initialize(); return MessageBox.Show(owner, text, caption, buttons, icon); } public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton) { _owner = owner; Initialize(); return MessageBox.Show(owner, text, caption, buttons, icon, defButton); } public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton, MessageBoxOptions options) { _owner = owner; Initialize(); return MessageBox.Show(owner, text, caption, buttons, icon, defButton, options); } public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); public delegate void TimerProc(IntPtr hWnd, uint uMsg, UIntPtr nIDEvent, uint dwTime); public const int WH_CALLWNDPROCRET = 12; public enum CbtHookAction : int { HCBT_MOVESIZE = 0, HCBT_MINMAX = 1, HCBT_QS = 2, HCBT_CREATEWND = 3, HCBT_DESTROYWND = 4, HCBT_ACTIVATE = 5, HCBT_CLICKSKIPPED = 6, HCBT_KEYSKIPPED = 7, HCBT_SYSCOMMAND = 8, HCBT_SETFOCUS = 9 } [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle lpRect); [DllImport("user32.dll")] private static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("User32.dll")] public static extern UIntPtr SetTimer(IntPtr hWnd, UIntPtr nIDEvent, uint uElapse, TimerProc lpTimerFunc); [DllImport("User32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll")] public static extern int UnhookWindowsHookEx(IntPtr idHook); [DllImport("user32.dll")] public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int maxLength); [DllImport("user32.dll")] public static extern int EndDialog(IntPtr hDlg, IntPtr nResult); [StructLayout(LayoutKind.Sequential)] public struct CWPRETSTRUCT { public IntPtr lResult; public IntPtr lParam; public IntPtr wParam; public uint message; public IntPtr hwnd; } ; static MessageBoxEx() { _hookProc = new HookProc(MessageBoxHookProc); _hHook = IntPtr.Zero; } private static void Initialize() { if (_hHook != IntPtr.Zero) { throw new NotSupportedException("multiple calls are not supported"); } if (_owner != null) { _hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, _hookProc, IntPtr.Zero, AppDomain.GetCurrentThreadId()); } } private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode < 0) { return CallNextHookEx(_hHook, nCode, wParam, lParam); } CWPRETSTRUCT msg = (CWPRETSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPRETSTRUCT)); IntPtr hook = _hHook; if (msg.message == (int)CbtHookAction.HCBT_ACTIVATE) { try { CenterWindow(msg.hwnd); } finally { UnhookWindowsHookEx(_hHook); _hHook = IntPtr.Zero; } } return CallNextHookEx(hook, nCode, wParam, lParam); } private static void CenterWindow(IntPtr hChildWnd) { Rectangle recChild = new Rectangle(0, 0, 0, 0); bool success = GetWindowRect(hChildWnd, ref recChild); int width = recChild.Width - recChild.X; int height = recChild.Height - recChild.Y; Rectangle recParent = new Rectangle(0, 0, 0, 0); success = GetWindowRect(_owner.Handle, ref recParent); Point ptCenter = new Point(0, 0); ptCenter.X = recParent.X + ((recParent.Width - recParent.X) / 2); ptCenter.Y = recParent.Y + ((recParent.Height - recParent.Y) / 2); Point ptStart = new Point(0, 0); ptStart.X = (ptCenter.X - (width / 2)); ptStart.Y = (ptCenter.Y - (height / 2)); ptStart.X = (ptStart.X < 0) ? 0 : ptStart.X; ptStart.Y = (ptStart.Y < 0) ? 0 : ptStart.Y; int result = MoveWindow(hChildWnd, ptStart.X, ptStart.Y, width, height, false); } } 

但为什么要停止与特定于MessageBox的实现? 使用下面的类如下所示:

  private void OnFormClosing(object sender, FormClosingEventArgs e) { DialogResult dg; using (DialogCenteringService centeringService = new DialogCenteringService(this)) // center message box { dg = MessageBox.Show(this, "Are you sure?", "Confirm exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question); } if (dg == DialogResult.No) { e.Cancel = true; } } 

您可以使用任何显示对话框窗口的代码,即使它们是由另一个线程拥有的(我们的应用程序有多个UI线程):

( 这里是更新后的代码,它将监视工作区域考虑在内,以便对话框不在两个监视器之间居中,或者部分地在屏幕外显示,因此需要enum SetWindowPosFlags ,如下所示)

 public class DialogCenteringService : IDisposable { private readonly IWin32Window owner; private readonly HookProc hookProc; private readonly IntPtr hHook = IntPtr.Zero; public DialogCenteringService(IWin32Window owner) { if (owner == null) throw new ArgumentNullException("owner"); this.owner = owner; hookProc = DialogHookProc; hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, hookProc, IntPtr.Zero, GetCurrentThreadId()); } private IntPtr DialogHookProc(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode < 0) { return CallNextHookEx(hHook, nCode, wParam, lParam); } CWPRETSTRUCT msg = (CWPRETSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPRETSTRUCT)); IntPtr hook = hHook; if (msg.message == (int)CbtHookAction.HCBT_ACTIVATE) { try { CenterWindow(msg.hwnd); } finally { UnhookWindowsHookEx(hHook); } } return CallNextHookEx(hook, nCode, wParam, lParam); } public void Dispose() { UnhookWindowsHookEx(hHook); } private void CenterWindow(IntPtr hChildWnd) { Rectangle recChild = new Rectangle(0, 0, 0, 0); bool success = GetWindowRect(hChildWnd, ref recChild); if (!success) { return; } int width = recChild.Width - recChild.X; int height = recChild.Height - recChild.Y; Rectangle recParent = new Rectangle(0, 0, 0, 0); success = GetWindowRect(owner.Handle, ref recParent); if (!success) { return; } Point ptCenter = new Point(0, 0); ptCenter.X = recParent.X + ((recParent.Width - recParent.X) / 2); ptCenter.Y = recParent.Y + ((recParent.Height - recParent.Y) / 2); Point ptStart = new Point(0, 0); ptStart.X = (ptCenter.X - (width / 2)); ptStart.Y = (ptCenter.Y - (height / 2)); //MoveWindow(hChildWnd, ptStart.X, ptStart.Y, width, height, false); Task.Factory.StartNew(() => SetWindowPos(hChildWnd, (IntPtr)0, ptStart.X, ptStart.Y, width, height, SetWindowPosFlags.SWP_ASYNCWINDOWPOS | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOZORDER)); } // some p/invoke // ReSharper disable InconsistentNaming public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); public delegate void TimerProc(IntPtr hWnd, uint uMsg, UIntPtr nIDEvent, uint dwTime); private const int WH_CALLWNDPROCRET = 12; // ReSharper disable EnumUnderlyingTypeIsInt private enum CbtHookAction : int // ReSharper restore EnumUnderlyingTypeIsInt { // ReSharper disable UnusedMember.Local HCBT_MOVESIZE = 0, HCBT_MINMAX = 1, HCBT_QS = 2, HCBT_CREATEWND = 3, HCBT_DESTROYWND = 4, HCBT_ACTIVATE = 5, HCBT_CLICKSKIPPED = 6, HCBT_KEYSKIPPED = 7, HCBT_SYSCOMMAND = 8, HCBT_SETFOCUS = 9 // ReSharper restore UnusedMember.Local } [DllImport("kernel32.dll")] static extern int GetCurrentThreadId(); [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle lpRect); [DllImport("user32.dll")] private static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags uFlags); [DllImport("User32.dll")] public static extern UIntPtr SetTimer(IntPtr hWnd, UIntPtr nIDEvent, uint uElapse, TimerProc lpTimerFunc); [DllImport("User32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll")] public static extern int UnhookWindowsHookEx(IntPtr idHook); [DllImport("user32.dll")] public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int maxLength); [DllImport("user32.dll")] public static extern int EndDialog(IntPtr hDlg, IntPtr nResult); [StructLayout(LayoutKind.Sequential)] public struct CWPRETSTRUCT { public IntPtr lResult; public IntPtr lParam; public IntPtr wParam; public uint message; public IntPtr hwnd; }; // ReSharper restore InconsistentNaming } [Flags] public enum SetWindowPosFlags : uint { // ReSharper disable InconsistentNaming /// <summary> /// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. /// </summary> SWP_ASYNCWINDOWPOS = 0x4000, /// <summary> /// Prevents generation of the WM_SYNCPAINT message. /// </summary> SWP_DEFERERASE = 0x2000, /// <summary> /// Draws a frame (defined in the window's class description) around the window. /// </summary> SWP_DRAWFRAME = 0x0020, /// <summary> /// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed. /// </summary> SWP_FRAMECHANGED = 0x0020, /// <summary> /// Hides the window. /// </summary> SWP_HIDEWINDOW = 0x0080, /// <summary> /// Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). /// </summary> SWP_NOACTIVATE = 0x0010, /// <summary> /// Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned. /// </summary> SWP_NOCOPYBITS = 0x0100, /// <summary> /// Retains the current position (ignores X and Y parameters). /// </summary> SWP_NOMOVE = 0x0002, /// <summary> /// Does not change the owner window's position in the Z order. /// </summary> SWP_NOOWNERZORDER = 0x0200, /// <summary> /// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing. /// </summary> SWP_NOREDRAW = 0x0008, /// <summary> /// Same as the SWP_NOOWNERZORDER flag. /// </summary> SWP_NOREPOSITION = 0x0200, /// <summary> /// Prevents the window from receiving the WM_WINDOWPOSCHANGING message. /// </summary> SWP_NOSENDCHANGING = 0x0400, /// <summary> /// Retains the current size (ignores the cx and cy parameters). /// </summary> SWP_NOSIZE = 0x0001, /// <summary> /// Retains the current Z order (ignores the hWndInsertAfter parameter). /// </summary> SWP_NOZORDER = 0x0004, /// <summary> /// Displays the window. /// </summary> SWP_SHOWWINDOW = 0x0040, // ReSharper restore InconsistentNaming } 

如果在背景(devise者)代码上稍微沉重一点,那么使用自己的面板或表单将是迄今为止最简单的方法。 它在alignment和操作方面提供了所有的控制,而无需编写所有的自定义代码。

我已经改变了一点以前的答案,并撰写了MessageBoxEx的WPF版本。 这段代码对我很好。 随时通知代码的问题。

请注意:我在ctor使用GeneralObjects.MainWindowInstance来初始化我的主窗口的类,但实际上我用它作为最后一个父窗口的某种caching的任何窗口。 因此,你可以简单地删除从ctor的一切。

 public class MessageBoxEx { private static HwndSource source_ = null; private static HwndSourceHook hook_ = null; static MessageBoxEx() { try { // create cached createHwndSource_(GeneralObjects.MainWindowInstance); hook_ = new HwndSourceHook(HwndSourceHook); } finally { if (null == source_ || null == hook_) { source_ = null; hook_ = null; } } } private static void createHwndSource_(Window owner) { source_ = (HwndSource)PresentationSource.FromVisual(owner); } public static void Initialize_(Window owner = null) { try { if (null != owner) { if(source_.RootVisual != owner) { createHwndSource_(owner); } } } finally { if (null == source_ || null == hook_) { source_ = null; hook_ = null; } } if (null != source_ && null != hook_) { source_.AddHook(hook_); } } public static MessageBoxResult Show(string messageBoxText) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText); } public static MessageBoxResult Show(string messageBoxText, string caption) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText, caption); } public static MessageBoxResult Show(Window owner, string messageBoxText) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText, caption, button); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText, caption); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText, caption, button, icon); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText, caption, button); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText, caption, button, icon, defaultResult); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText, caption, button, icon); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, System.Windows.MessageBoxOptions options) { Initialize_(); return System.Windows.MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, System.Windows.MessageBoxOptions options) { Initialize_(owner); return System.Windows.MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult, options); } private enum WM : int { WM_ACTIVATE = 0x0006 } private static IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if ((int)WM.WM_ACTIVATE == msg && source_.Handle == hwnd && 0 == (int)wParam) { try { CenterWindow(lParam); } finally { // remove hook at once after moved message box window. source_.RemoveHook(hook_); } } return IntPtr.Zero; } [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle lpRect); [DllImport("user32.dll")] private static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); private static void CenterWindow(IntPtr hChildWnd) { System.Drawing.Rectangle recChild = new System.Drawing.Rectangle(0, 0, 0, 0); bool success = GetWindowRect(hChildWnd, ref recChild); int width = recChild.Width - recChild.X; int height = recChild.Height - recChild.Y; System.Drawing.Rectangle recParent = new System.Drawing.Rectangle(0, 0, 0, 0); success = GetWindowRect(source_.Handle, ref recParent); System.Drawing.Point ptCenter = new System.Drawing.Point(0, 0); ptCenter.X = recParent.X + ((recParent.Width - recParent.X) / 2); ptCenter.Y = recParent.Y + ((recParent.Height - recParent.Y) / 2); System.Drawing.Point ptStart = new System.Drawing.Point(0, 0); ptStart.X = (ptCenter.X - (width / 2)); ptStart.Y = (ptCenter.Y - (height / 2)); // I have commented this code because of I have 2 monitors // so If application located at 1st monitor // message box can appear at second one. /* ptStart.X = (ptStart.X < 0) ? 0 : ptStart.X; ptStart.Y = (ptStart.Y < 0) ? 0 : ptStart.Y; */ int result = MoveWindow(hChildWnd, ptStart.X, ptStart.Y, width, height, false); } } 

试试这个,它足够简单,足以certificate时间…

这是用C编写的Win32 API。根据需要翻译它…

 case WM_NOTIFY:{ HWND X=FindWindow("#32770",NULL); if(GetParent(X)==H_frame){int Px,Py,Sx,Sy; RECT R1,R2; GetWindowRect(hwnd,&R1); GetWindowRect(X,&R2); Sx=R2.right-R2.left,Px=R1.left+(R1.right-R1.left)/2-Sx/2; Sy=R2.bottom-R2.top,Py=R1.top+(R1.bottom-R1.top)/2-Sy/2; MoveWindow(X,Px,Py,Sx,Sy,1); } } break; 

将其添加到WndProc代码中…您可以根据需要设置位置,在这种情况下,它只是在主程序窗口的中心位置。 它会为任何消息框,或文件打开/保存对话框,以及可能的一些其他本地控制。 我不知道,但我想你可能需要包括COMMCTRL或COMMDLG来使用这个,至less,如果你想要打开/保存对话框。

我试着查看NMHDR的通知代码和hwndFrom,然后确定它同样有效,而且更容易,而不是。 如果您真的想要非常具体,请告诉FindWindow查找您要查找的窗口的唯一标题(标题)。

在屏幕上绘制消息框之前触发,所以如果您设置一个全局标志来指示何时由您的代码执行操作,并查找唯一标题,则确保您执行的操作只会发生一次(可能会有多个通知程序)。 我没有详细探讨这一点,但我pipe理得到CreateWindow把一个编辑框放在一个消息框对话框。 它看起来像一个老鼠的耳朵嫁接到一只克隆猪的脊椎上,但它的工作原理。 以这种方式做事可能比自己做起来要容易得多。

乌鸦。

编辑:小的更正,以确保正确的窗口处理。 确保父母的手柄一致,这应该工作。 它对我来说,即使有两个相同的程序实例…