Winforms如何使MessageBox以MainForm为中心显示?

Winforms如何使MessageBox以MainForm为中心显示?,winforms,messagebox,Winforms,Messagebox,Winforms如何使对话框以MainForm为中心显示?这与基于正常窗口默认设置的情况相反,正常窗口默认设置将它们显示在屏幕的中心 在我的例子中,我有一个小的主窗体,例如可以放在一个角落里,MessageBox弹出窗口显示在远处 通过p/Invoke的某些服务和Control.BeginInvoke()提供的魔力,这是可能的。向项目中添加新类并粘贴以下代码: using System; using System.Text; using System.Drawing; using System.

Winforms如何使对话框以MainForm为中心显示?这与基于正常窗口默认设置的情况相反,正常窗口默认设置将它们显示在屏幕的中心


在我的例子中,我有一个小的主窗体,例如可以放在一个角落里,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; }
}

请注意,此代码适用于任何Windows对话框。MessageBox、OpenFormDialog、FolderBrowserDialog、PrintDialog、ColorDialog、FontDialog、PageSetupDialog、SaveFileDialog。编写您自己的MessageBox。一个表单和一个标签就可以了。或者您还需要全球化它吗?

这是针对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;
将其添加到WndProc代码中。。。您可以根据需要设置位置,在这种情况下,它仅位于主程序窗口的中心。它将对任何messagebox、文件打开/保存对话框以及其他一些本机控件执行此操作。我不确定,但我认为您可能需要包括COMMCTRL或COMMDLG来使用它,至少,如果您想要打开/保存对话框,您可以这样做

我尝试查看NMHDR的通知代码和hwndFrom,然后认为它同样有效,而且更容易实现。如果你真的想说得非常具体,告诉FindWindow去寻找你给你想让它找到的窗口的唯一标题(title)

这会在messagebox在屏幕上绘制之前触发,因此,如果您设置了一个全局标志来指示代码何时执行操作,并查找唯一的标题,则可以确保您执行的操作只发生一次(可能会有多个通知程序)。我还没有详细探讨过这一点,但我设法让CreateWindow在messagebox对话框上放置了一个编辑框/它看起来像老鼠的耳朵移植到克隆猪的脊柱上一样不合适,但它可以工作。用这种方式做事可能比自己动手要容易得多

乌鸦


编辑:小的修正以确保正确的窗口被处理。确保整个过程中父句柄都一致,这应该可以正常工作。对我来说确实如此,即使是同一程序的两个实例…

该类被证明适用于其他两种情况。我有一个FolderBrowser对话框,我希望它更大一些,我希望它出现在父对话框的左上角附近(靠近我单击打开它的按钮)

我复制了CenterWinDialog类并创建了两个新类。一个类更改对话框大小,另一个类将其位置更改为相对于父窗体的特定偏移量。这是用法:

        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 OffsetWinDialog:IDisposable
{
私有整数mTries=0;
私人割草机;
公共OffsetWinDialog(表格所有者)
{
割草机=所有者;
owner.BeginInvoke(新方法调用程序(findDialog));
}
公共点PreferredOffset{get;set;}
私有void findDialog()
{
//枚举窗口以查找消息框
如果(mTries<0)
返回;
EnumThreadWndProc回调=新建EnumThreadWndProc(检查窗口);
if(EnumThreadWindows(GetCurrentThreadId(),回调,IntPtr.Zero))
{
如果(++mTries<10)
BeginInvoke(新方法调用程序(findDialog));
}
}
专用布尔检查窗口(IntPtr hWnd、IntPtr lp)
{
//检查是否为对话框
StringBuilder sb=新StringBuilder(260);
GetClassName(hWnd、sb、sb容量);
如果(sb.ToString()!=“#32770”)返回true;
//明白了
矩形frmRect=新矩形(割草机位置、割草机大小);
直截了当;
GetWindowRect(hWnd,out dlgRect);
移动窗口(hWnd,
frmRect.Left+PreferredOffset.X,
frmRect.Top+首选项偏移量.Y,
dlgRect.Right-dlgRect.Left,
dlgRect.Bottom-dlgRect.Top,
正确的);
返回false;
}
公共空间处置()
{
mTries=-1;
}
//P/Invoke声明
私人代表bool EnumThreadWndProc(IntPtr hWnd,IntPtr lp);
[DllImport(“user32.dll”)]
私有静态外部布尔EnumThreadWindows(int tid、EnumThreadWndProc回调、IntPtr lp);
[DllImport(“kernel32.dll”)]
私有静态外部int GetCurrentThreadId();
[DllImport(“user32.dll”)]
私有静态外部int GetClassName(IntPtr hWnd、StringBuilder缓冲区、int buflen);
[DllImport(“user32.dll”)]
私有静态外部bool GetWindowRect(IntPtr hWnd,out RECT rc);
[DllImport(“user32.dll”)]
私有静态外部布尔移动窗口(IntPtr hWnd、intx、inty、intw、inth、布尔重绘);
私有结构RECT{public int Left;public int Top;public int Right;public int Bottom;}
}

类大小indialog:IDisposable
{
私有整数mTries=0;
私人割草机;
公共大小索引(表格所有者)
{
割草机=所有者;
mOwner.BeginInvoke(新行动(findDialog));
}
公共大小首选大小{get;set;}
私有void findDialog()
{
//枚举窗口以查找消息框
如果(mTries<0)
返回;
EnumThreadWndProc回调=新建EnumThreadWndProc(检查窗口);
if(EnumThreadWindows(GetCurrentThreadId(),回调,IntPtr.Zero))
{
如果(++mTries<10)
BeginInvoke(新方法调用程序(findDialog));
}
}
专用布尔检查窗口(IntPtr hWnd、IntPtr lp)
{
//检查是否为对话框
StringBuilder sb=新StringBuilder(260);
GetClassName(hWnd、sb、sb容量);
如果(某人)
返回true;
//明白了
矩形frmRect=新矩形(割草机位置,割草机)
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; }
}
 public partial class __MessageBox : Form
   {
      public MMMessageBox(string title, string message)
      {
         InitializeComponent();
         this.Text = title;
         this.labelString.Text = message;
      }
   }