Winforms – Wie kann ich MessageBox auf MainForm zentriert erscheinen lassen?

Winforms – Wie kann ich Dialogfelder zentriert auf MainForm erscheinen lassen? Das ist im Gegensatz zu dem Standard-Windows-Standard, der sie in der Mitte des Bildschirms rendert.

In meinem Fall habe ich ein kleines Hauptformular, das zum Beispiel in einer Ecke positioniert werden kann, das MessageBox-Popup wird angezeigt, was weit weg scheint.

    Es ist mit einigen Portionen von P / Invoke und der Magie von Control.BeginInvoke () möglich. Fügen Sie Ihrem Projekt eine neue class hinzu und fügen Sie diesen Code ein:

     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  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; } } 

    Beispielverwendung:

      private void button1_Click(object sender, EventArgs e) { using (new CenterWinDialog(this)) { MessageBox.Show("Nobugz waz here"); } } 

    Beachten Sie, dass dieser Code für alle Windows-Dialoge funktioniert. MessageBox, OpenFormDialog, FolderBrowserDialog, PrintDialog, ColorDialog, FontDialog, PageSetupDialog, SaveFileDialog.

    Dies ist für Win32-API, in C geschrieben. Übersetzen Sie es, wie Sie brauchen …

     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; 

    Fügen Sie das dem WndProc-Code hinzu … Sie können die Position beliebig setzen, in diesem Fall zentriert sie sich einfach über dem Hauptprogrammfenster. Es wird dies für jede Meldungsbox oder jeden Dialog zum Öffnen / Speichern von Dateien und wahrscheinlich für andere native Steuerelemente tun. Ich bin mir nicht sicher, aber ich denke, Sie müssen COMMCTRL oder COMMDLG enthalten, um dies zu verwenden, zumindest, wenn Sie Dialoge öffnen / speichern wollen.

    Ich experimentierte mit den Benachrichtigungscodes und hwndFrom von NMHDR und entschied dann, dass es genauso effektiv und viel einfacher war, nicht. Wenn Sie wirklich sehr spezifisch sein möchten, sagen Sie FindWindow, nach einer eindeutigen Beschriftung (Titel) zu suchen, die Sie dem Fenster geben, das Sie finden möchten.

    Dies wird ausgetriggers, bevor die Meldungsbox am Bildschirm angezeigt wird. Wenn Sie also ein globales Flag setzen, um anzuzeigen, wann der Code ausgeführt wird, und nach einer eindeutigen Beschriftung zu suchen, werden Sie sicher sein, dass die Aktionen nur einmal ausgeführt werden Anmelder). Ich habe das nicht im Detail untersucht, aber es gelang mir, CreateWindow dazu zu bringen, ein Bearbeitungsfeld in einen MessageBox-Dialog zu stellen. Es sah so fehl am Platz wie ein Rattenohr auf den Rücken eines geklonten Schweins, aber es funktioniert. Dinge auf diese Weise zu tun, kann viel einfacher sein, als selbst rollen zu müssen.

    Krähe.

    EDIT: Kleine Korrektur, um sicherzustellen, dass das richtige Fenster behandelt wird. Stellen Sie sicher, dass die übergreifenden Handles durchgängig übereinstimmen, und dies sollte in Ordnung funktionieren. Es macht für mich, sogar mit zwei Instanzen des gleichen Programms …

    Schreiben Sie Ihre eigene Nachrichtenbox. Ein Formular und ein Label sollten es tun. Oder müssen Sie es auch globalisieren?

    Die class erwies sich in zwei anderen Situationen als anwendbar. Ich hatte einen FolderBrowserDialog, der größer sein sollte, und ich wollte, dass er oben links im Elterndialog erscheint (in der Nähe der Schaltfläche, auf die ich klicke, um ihn zu öffnen).

    Ich habe die CenterWinDialog-class kopiert und zwei neue classn erstellt. Eine class ändert die Größe des Dialogfelds und die andere ändert ihre Position in einen bestimmten Abstand vom übergeordneten Formular. Dies ist die Verwendung:

      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; } 

    und das sind die zwei classn, die auf dem ursprünglichen basieren.

     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  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; } } 

    und

     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  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; } }