aepot Asked:2023-06-10 00:24:27 +0000 UTC2023-06-10 00:24:27 +0000 UTC 2023-06-10 00:24:27 +0000 UTC 如何在 Windows 窗体和 WPF 中将 MessageBox 居中? 772 要使弹出对话框居中于父窗口的中心,您可以实现自己的对话框并使用它代替MessageBox. 但有时这是多余的,您需要以一种简单而熟悉的方式使用它,而且如果您有一个旧项目,您可以改进它的行为而无需花费大量时间进行修改。 MessageBox默认弹出在屏幕中央,但是如何让它在窗口中央呢? c# 1 个回答 Voted Best Answer aepot 2023-06-10T00:24:27Z2023-06-10T00:24:27Z 没有现成的方法,Windows不支持这样的技巧。但是你可以自己实现。 我有一个已经实施了很长时间的解决方案,我称之为MessageBoxEx,我决定分享它。 WPF 的 Requires类MessageBoxEx需要安装 NuGet 包System.Drawing.Common。Winforms 默认包含此包,因此无需安装。 using System.Drawing; 以下是完成的课程: Windows 窗体 public static class MessageBoxEx { private static Form _owner; private static readonly HookProc _hookProc = new HookProc(MessageBoxHookProc); private static IntPtr _hHook = IntPtr.Zero; public static DialogResult Show(Form owner, string text) { Initialize(owner); return MessageBox.Show(owner, text); } public static DialogResult Show(Form owner, string text, string caption) { Initialize(owner); return MessageBox.Show(owner, text, caption); } public static DialogResult Show(Form owner, string text, string caption, MessageBoxButtons buttons) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons); } public static DialogResult Show(Form owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon); } public static DialogResult Show(Form owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon, defButton); } public static DialogResult Show(Form owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton, MessageBoxOptions options) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon, defButton, options); } private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); private const int WH_CALLWNDPROCRET = 12; private 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")] private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll")] private static extern int UnhookWindowsHookEx(IntPtr idHook); [DllImport("user32.dll")] private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll")] private static extern int GetCurrentThreadId(); [StructLayout(LayoutKind.Sequential)] private struct CWPRETSTRUCT { public IntPtr lResult; public IntPtr lParam; public IntPtr wParam; public CbtHookAction message; public IntPtr hwnd; }; private static void Initialize(Form owner) { _owner = owner; if (owner is Form form && form.WindowState == FormWindowState.Normal) { if (_hHook != IntPtr.Zero) { throw new NotSupportedException("Multiple calls are not supported"); } _hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, _hookProc, IntPtr.Zero, GetCurrentThreadId()); } } private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode < 0) { return CallNextHookEx(_hHook, nCode, wParam, lParam); } CWPRETSTRUCT msg = Marshal.PtrToStructure<CWPRETSTRUCT>(lParam); IntPtr hook = _hHook; if (msg.message == 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) { if (_owner is Form form) { Rectangle recChild = new Rectangle(0, 0, 0, 0); _ = GetWindowRect(hChildWnd, ref recChild); int width = recChild.Width - recChild.X; int height = recChild.Height - recChild.Y; int x = form.Left + ((form.Width - width) / 2); int y = form.Top + ((form.Height - height) / 2); _ = MoveWindow(hChildWnd, x, y, width, height, false); } } } WPF public static class MessageBoxEx { private static Window _owner; private static readonly HookProc _hookProc = new HookProc(MessageBoxHookProc); private static IntPtr _hHook = IntPtr.Zero; public static MessageBoxResult Show(Window owner, string text) { Initialize(owner); return MessageBox.Show(owner, text); } public static MessageBoxResult Show(Window owner, string text, string caption) { Initialize(owner); return MessageBox.Show(owner, text, caption); } public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons); } public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon); } public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defButton) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon, defButton); } public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defButton, MessageBoxOptions options) { Initialize(owner); return MessageBox.Show(owner, text, caption, buttons, icon, defButton, options); } private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); private const int WH_CALLWNDPROCRET = 12; private 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")] private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll")] private static extern int UnhookWindowsHookEx(IntPtr idHook); [DllImport("user32.dll")] private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll")] private static extern int GetCurrentThreadId(); [StructLayout(LayoutKind.Sequential)] private struct CWPRETSTRUCT { public IntPtr lResult; public IntPtr lParam; public IntPtr wParam; public CbtHookAction message; public IntPtr hwnd; }; private static void Initialize(Window owner) { _owner = owner; if (owner is Window window && window.WindowState == WindowState.Normal) { if (_hHook != IntPtr.Zero) { throw new NotSupportedException("Multiple calls are not supported"); } _hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, _hookProc, IntPtr.Zero, GetCurrentThreadId()); } } private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode < 0) { return CallNextHookEx(_hHook, nCode, wParam, lParam); } CWPRETSTRUCT msg = Marshal.PtrToStructure<CWPRETSTRUCT>(lParam); IntPtr hook = _hHook; if (msg.message == 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) { if (_owner is Window window) { Rectangle recChild = new Rectangle(0, 0, 0, 0); _ = GetWindowRect(hChildWnd, ref recChild); int width = recChild.Width - recChild.X; int height = recChild.Height - recChild.Y; PresentationSource source = PresentationSource.FromVisual(window); double scaleX = source.CompositionTarget.TransformToDevice.M11; double scaleY = source.CompositionTarget.TransformToDevice.M22; int x = (int)((window.Left + (window.Width - width / scaleX) / 2) * scaleX); int y = (int)((window.Top + (window.Height - height / scaleY) / 2) * scaleY); _ = MoveWindow(hChildWnd, x, y, width, height, false); } } } 如您所见,这两个类几乎相同,但适用于所需的 UI 引擎。 用法 就像通常的一样MessageBox,只有第一个参数是传递相对于它应该居中的窗口(或窗体)。 Winforms 和 WPF 的用法是一样的: MessageBoxEx.Show(this, "Hello World"); this它在哪里Form用于 Winforms 或WindowWPF。
没有现成的方法,Windows不支持这样的技巧。但是你可以自己实现。
我有一个已经实施了很长时间的解决方案,我称之为
MessageBoxEx,我决定分享它。WPF 的 Requires类
MessageBoxEx需要安装 NuGet 包System.Drawing.Common。Winforms 默认包含此包,因此无需安装。以下是完成的课程:
Windows 窗体
WPF
如您所见,这两个类几乎相同,但适用于所需的 UI 引擎。
用法
就像通常的一样
MessageBox,只有第一个参数是传递相对于它应该居中的窗口(或窗体)。Winforms 和 WPF 的用法是一样的:
this它在哪里Form用于 Winforms 或WindowWPF。