Winforms - 如何让MessageBox出现在MainForm的中心?

问题描述:

Winforms - 如何使对话框出现在MainForm中心?这与基于Normal窗口的默认设置相反,后者将它们呈现在屏幕的中心。Winforms - 如何让MessageBox出现在MainForm的中心?

在我的情况下,我有一个小的主窗体,例如可以放置在一个角落,MessageBox弹出窗口显示什么似乎离开。

+1

'使用(NewFormDialog newDialog =新NewFormDialog()){newDialog.StartPosition = FormStartPosition.CenterParent; newDialog.ShowDialog(); };' – uSeRnAmEhAhAhAhAhA 2013-10-10 05:30:50

它可能与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。

+0

谢谢,非常好的解决方案。你只需要改变它不使用'this'这是多余的。只需采取最佳形式。 – c00000fd 2013-10-21 04:29:47

+0

我改编了WPF代码,它工作正常:D – monstr 2014-12-02 08:20:20

+0

最好的+10000000000000 – vietnguyen09 2015-08-18 12:58:06

写你自己的messagebox。表单和标签应该这样做。或者你还需要将其全球化?

+0

不需要全球化 – Greg 2010-04-04 23:33:27

+0

在这种情况下,您可以向表单添加标签并使用MeasureString获取它的边界。适当调整表格的大小,并将其放在任何你喜欢的地方。应该很快。 但我必须承认我也喜欢Nobugz的解决方案。 – Pedery 2010-04-05 02:17:55

这是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的代码。您可以设置位置,只要你喜欢,在这种情况下,只是在主程序窗口的中心。它会为任何消息框,文件打开/保存对话框以及可能的其他本机控件执行此操作。我不确定,但我想你可能需要包含COMMCTRL或COMMDLG来使用它,至少,如果你想打开/保存对话框,你会。

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

此消息在屏幕上绘制之前触发,因此如果您设置全局标志以指示何时由代码完成操作并查找唯一标题,则确保您执行的操作只会发生一次将可能是多个通知器)。我还没有详细探讨这一点,但我设法让CreateWindow在一个消息框对话框中放置一个编辑框/它看起来不合适,就像老鼠的耳朵嫁接到克隆猪的脊椎上一样,但它很有效。以这种方式做事可能比自己做起来要容易得多。

乌鸦。

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

该类证明适用于其他两种情况。我有一个FolderBrowserDialog,我想要更大一些,并且我希望它靠近父对话框的左上角(靠近按钮点击打开它)。

我复制了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 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; } 
}