2010-04-04 27 views
37

Winforms - 如何使對話框出現在MainForm中心?這與基於Normal窗口的默認設置相反,後者將它們呈現在屏幕的中心。Winforms - 如何讓MessageBox出現在MainForm的中心?

在我的情況下,我有一個小的主窗體,例如可以放置在一個角落,MessageBox彈出窗口顯示什麼似乎離開。

+1

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

回答

48

它可能與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

1

寫你自己的messagebox。表單和標籤應該這樣做。或者你還需要將其全球化?

+0

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

+0

在這種情況下,您可以向表單添加標籤並使用MeasureString獲取它的邊界。適當調整表格的大小,並將其放在任何你喜歡的地方。應該很快。 但我必須承認我也喜歡Nobugz的解決方案。 – Pedery 2010-04-05 02:17:55

2

這是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在一個消息框對話框中放置一個編輯框/它看起來不合適,就像老鼠的耳朵嫁接到克隆豬的脊椎上一樣,但它很有效。以這種方式做事可能比自己做起來要容易得多。

烏鴉。

編輯:小的更正,以確保正確的窗口處理。確保父母手柄始終保持一致,並且這應該可以正常工作。它對我來說,即使有兩個相同的程序實例...

1

該類證明適用於其他兩種情況。我有一個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; } 
}