Winforms-如何使对话框出现在主窗体的中心?而不是基于普通窗口默认方式,该方式将它们呈现在屏幕中央。
在我的情况下,我有一个小的主窗体,可能被放置在一个角落,当MessageBox弹出时,它似乎离得很远。
Winforms-如何使对话框出现在主窗体的中心?而不是基于普通窗口默认方式,该方式将它们呈现在屏幕中央。
在我的情况下,我有一个小的主窗体,可能被放置在一个角落,当MessageBox弹出时,它似乎离得很远。
通过一些 P/Invoke 的用法和 Control.BeginInvoke() 提供的魔力,这是可能的。在您的项目中添加一个新类并粘贴以下代码:
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class CenterWinDialog : IDisposable {
private int mTries = 0;
private Form mOwner;
public CenterWinDialog(Form owner) {
mOwner = owner;
owner.BeginInvoke(new MethodInvoker(findDialog));
}
private void findDialog() {
// Enumerate windows to find the message box
if (mTries < 0) return;
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero)) {
if (++mTries < 10) mOwner.BeginInvoke(new MethodInvoker(findDialog));
}
}
private bool checkWindow(IntPtr hWnd, IntPtr lp) {
// Checks if <hWnd> is a dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() != "#32770") return true;
// Got it
Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
RECT dlgRect;
GetWindowRect(hWnd, out dlgRect);
MoveWindow(hWnd,
frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
dlgRect.Right - dlgRect.Left,
dlgRect.Bottom - dlgRect.Top, true);
return false;
}
public void Dispose() {
mTries = -1;
}
// P/Invoke declarations
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}
使用示例:
private void button1_Click(object sender, EventArgs e) {
using (new CenterWinDialog(this)) {
MessageBox.Show("Nobugz waz here");
}
}
请注意,此代码适用于任何 Windows 对话框。MessageBox、OpenFormDialog、FolderBrowserDialog、PrintDialog、ColorDialog、FontDialog、PageSetupDialog、SaveFileDialog。
this
关键字。直接使用顶层表单即可。 - c00000fdowner.BeginInvoke
之前加入 if (owner.WindowState != FormWindowState.Minimized)
这段代码,以在这种情况下禁用它。请注意,这不会改变原有的意思。 - Nyerguds这是关于Win32 API的内容,使用C语言编写。您可以根据需要进行翻译...
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;
using (new OffsetWinDialog(this) { PreferredOffset = new Point(75, 75 )})
using (new SizeWinDialog(this) { PreferredSize = new Size(400, 600)})
{
DialogResult result = dlgFolderBrowser.ShowDialog();
if (result == DialogResult.Cancel)
return;
}
这是基于原始类创建的两个类。
class OffsetWinDialog : IDisposable
{
private int mTries = 0;
private Form mOwner;
public OffsetWinDialog(Form owner)
{
mOwner = owner;
owner.BeginInvoke(new MethodInvoker(findDialog));
}
public Point PreferredOffset { get; set; }
private void findDialog()
{
// Enumerate windows to find the message box
if (mTries < 0)
return;
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
{
if (++mTries < 10)
mOwner.BeginInvoke(new MethodInvoker(findDialog));
}
}
private bool checkWindow(IntPtr hWnd, IntPtr lp)
{
// Checks if <hWnd> is a dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() != "#32770") return true;
// Got it
Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
RECT dlgRect;
GetWindowRect(hWnd, out dlgRect);
MoveWindow(hWnd,
frmRect.Left + PreferredOffset.X,
frmRect.Top + PreferredOffset.Y,
dlgRect.Right - dlgRect.Left,
dlgRect.Bottom - dlgRect.Top,
true);
return false;
}
public void Dispose()
{
mTries = -1;
}
// P/Invoke declarations
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}
和
class SizeWinDialog : IDisposable
{
private int mTries = 0;
private Form mOwner;
public SizeWinDialog(Form owner)
{
mOwner = owner;
mOwner.BeginInvoke(new Action(findDialog));
}
public Size PreferredSize { get; set; }
private void findDialog()
{
// Enumerate windows to find the message box
if (mTries < 0)
return;
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
{
if (++mTries < 10)
mOwner.BeginInvoke(new MethodInvoker(findDialog));
}
}
private bool checkWindow(IntPtr hWnd, IntPtr lp)
{
// Checks if <hWnd> is a dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() != "#32770")
return true;
// Got it
Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
RECT dlgRect;
GetWindowRect(hWnd, out dlgRect);
SetWindowPos(new HandleRef(this, hWnd), new HandleRef(), dlgRect.Left, dlgRect.Top, PreferredSize.Width, PreferredSize.Height, 20 | 2);
return false;
}
public void Dispose()
{
mTries = -1;
}
// P/Invoke declarations
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool SetWindowPos(HandleRef hWnd, HandleRef hWndInsertAfter, int x, int y, int cx, int cy,
int flags);
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}
编写自己的消息框。一个窗体和一个标签就可以了。或者你还需要全球化吗?
不需要使用自制消息框或者GetForegroundWindow、EnumWindows、AutomationElement.RootElement.FindAll、SetWindowsHookEx等方法。
当消息框被打开或关闭时,WM_ACTIVATE消息会被发送到表单。
然后,您可以获取消息框的窗口句柄(LParam)。
protected override void WndProc(ref Message m)
{
switch (m.Msg) {
case Pinvoke.WM_ACTIVATE:
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name} {DateTime.Now.ToString("HH:mm:ss.fff")} {m.ToString()}");
if (m.LParam == IntPtr.Zero) break;
if (_messageBoxCaption == null) break; // donot call MessageBox.Show
if ((ushort)m.WParam.ToInt32() != 0/*WA_INACTIVE*/) break; // maybe close messagebox
// check messagebox
if (Pinvoke.GetWindowProcessId(m.LParam) != Process.GetCurrentProcess().Id) break;
string className = Pinvoke.GetClassName(m.LParam);
if (className == null || className != "#32770") break; // not dialog
if (_messageBoxCaption != Pinvoke.GetWindowText(m.LParam)) break; // another caption
// move messagebox
//Debug.WriteLine("messageBox detected");
Rectangle rect = Pinvoke.GetWindowRect(m.LParam);
Pinvoke.MoveWindow(m.LParam, this.Left + this.Width / 2, this.Top + this.Height / 2, rect.Width, rect.Height, true);
break;
}
base.WndProc(ref m);
}
GetWindowProcessId是GetWindowThreadProcessId的包装器。 根据需要添加其他Pinvoke方法。 如果您想尽可能减少P/Invoke,请使用UIAutomation替换它们。
private string _messageBoxCaption = null; // messageBox caption
_messageBoxCaption = caption;
ret = MessageBox.Show(this, text, caption, ...);
_messageBoxCaption = null;
创建你自己的...
public partial class __MessageBox : Form
{
public MMMessageBox(string title, string message)
{
InitializeComponent();
this.Text = title;
this.labelString.Text = message;
}
}
using(NewFormDialog newDialog = new NewFormDialog()) { newDialog.StartPosition = FormStartPosition.CenterParent; newDialog.ShowDialog(); };
- uSeRnAmEhAhAhAhAhA