none
Wie positioniert man eine Messagebox RRS feed

  • Frage

  • Hallo

    ich suche nach einem einfachen Weg, eine Messagebox zentriert oder zumindest irgendwo auf der Form anzuzeigen und nicht an irgendeinen Platz auf dem Bildschirm . Die Angabe eines Controls im Aufruf von Show zeigt keine Wirkung.

    Samstag, 8. Mai 2010 08:42

Antworten

  • Hallo,

    die Standard Message Box lässt sich nicht einfach positionieren. Sie wird immer in der Bildschirmmitte angezeigt. Über einen Hook kann man in den Erstellungsprozess eingreifen und die MessageBox ausrichten.

    Centering MessageBox, Common DialogBox or Form on applications
    http://www.codeproject.com/KB/dialog/CenterDialog.aspx

    Alternative wäre ggf. ein eigenes Formular. Hier ergibt sich der Aufwand jedoch daraus, dieses Formular so nachzubauen, dass es für den Anwender wie eine normale MessageBox aussieht und sich auch so verhält. Bezüglich des Verhaltens, spricht eigentlich bereits die manuelle Ausrichtung gegen jeglichen Eingriff, denn dass die MessageBox in der Bildschirmmitte erscheint, dürfte dem Anwender vertraut vorkommen.

    Als Owner legt man übrigens kein Control fest, sondern ein Formular. Üblicherweise, das aus dem die MessageBox aufgerufen wurde.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Samstag, 8. Mai 2010 11:17
    Beantworter
  • Hallo JoHom,

    Die System.Windows.Forms.MessageBox kapselt die Windows API-Funktion MessageBox() aus der user32.dll. Diese bietet leider keine eingebaute Funktionalität zum Zentrieren des Meldungs-Fensters. Der einfachste mir bekannte Weg eine Standard-MessageBox zu zentrieren, geht - wie schon Thorsten schrieb - über die Verwendung eines CBT-Hooks.

    s.a. How To Position a MsgBox Using a Windows Hook Procedure:
    http://support.microsoft.com/kb/180936/en-us

    Hier ist die C#-Portierung des MSDN-Beispiels aus dem o.g. Link:

    namespace CenteredMessageBox
    {
     using System;
     using System.Runtime.InteropServices;
     using System.Windows.Forms;
    
     public static class MessageBoxEx
     {
      private const int GWL_HINSTANCE = -0x6;
      private const int SWP_NOSIZE = 0x1;
      private const int SWP_NOZORDER = 0x4;
      private const int SWP_NOACTIVATE = 0x10;
      private const int HCBT_ACTIVATE = 0x5;
      private const int WH_CBT = 0x5;
    
      private static RECT rectMsgBox;
      private static RECT rectForm;
      private static int hook;
    
      private delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    
      public static DialogResult ShowCentered(Form parentForm, string message)
      {
       return ShowCentered(parentForm, message, String.Empty, MessageBoxButtons.OK, MessageBoxIcon.None);
      }
    
      public static DialogResult ShowCentered(Form parentForm, string message, string title)
      {
       return ShowCentered(parentForm, message, title, MessageBoxButtons.OK, MessageBoxIcon.None);
      }
    
      public static DialogResult ShowCentered(Form parentForm, string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
      {
       if (hook == 0)
       {
        rectForm = new RECT() { Bottom = parentForm.Bottom, Left = parentForm.Left, Right = parentForm.Right, Top = parentForm.Top };
        IntPtr instanceHandle = GetWindowLongPtr(parentForm.Handle, GWL_HINSTANCE);
        int threadId = AppDomain.GetCurrentThreadId();
        hook = SetWindowsHookEx(WH_CBT, WinProc1, instanceHandle, threadId);
       }
    
       return MessageBox.Show(parentForm, message, title, buttons, icon);
      }
    
      private static int WinProc1(int nCode, IntPtr wParam, IntPtr lParam)
      {
       if (nCode == HCBT_ACTIVATE)
       {
        HandleRef handle = new HandleRef(rectForm, wParam);
        if (GetWindowRect(handle, out rectMsgBox))
        {
         int x = (rectForm.Left + ((rectForm.Right - rectForm.Left) / 2)) - ((rectMsgBox.Right - rectMsgBox.Left) / 2);
         int y = (rectForm.Top + ((rectForm.Bottom - rectForm.Top) / 2)) - ((rectMsgBox.Bottom - rectMsgBox.Top) / 2);
    
         SetWindowPos(wParam, IntPtr.Zero, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
         UnhookWindowsHookEx(hook);
         hook = 0;
        }
       }
    
       return 0;
      }
    
      [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
      private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    
      [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
      private static extern bool UnhookWindowsHookEx(int idHook);
    
      [DllImport("user32.dll", EntryPoint = "GetWindowLong")] // EntryPoint="GetWindowLongPtr" on 64-bit
      private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
    
      [DllImport("user32.dll", SetLastError = true)]
      [return: MarshalAs(UnmanagedType.Bool)]
      private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      private static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
    
      [DllImport("kernel32.dll")]
      private static extern uint GetCurrentThreadId();
    
      [StructLayout(LayoutKind.Sequential)]
      private struct RECT
      {
       public int Left;
       public int Top;
       public int Right;
       public int Bottom;
      }
     }
    }
    

    Der Aufruf ist dann denkbar einfach:

    MessageBoxEx.ShowCentered(this, "Diese Meldung wird zentriert angezeigt.", "Test");

     

    Gruss
    Marcel

    Mittwoch, 12. Mai 2010 12:39

Alle Antworten

  • Hallo,

    die Standard Message Box lässt sich nicht einfach positionieren. Sie wird immer in der Bildschirmmitte angezeigt. Über einen Hook kann man in den Erstellungsprozess eingreifen und die MessageBox ausrichten.

    Centering MessageBox, Common DialogBox or Form on applications
    http://www.codeproject.com/KB/dialog/CenterDialog.aspx

    Alternative wäre ggf. ein eigenes Formular. Hier ergibt sich der Aufwand jedoch daraus, dieses Formular so nachzubauen, dass es für den Anwender wie eine normale MessageBox aussieht und sich auch so verhält. Bezüglich des Verhaltens, spricht eigentlich bereits die manuelle Ausrichtung gegen jeglichen Eingriff, denn dass die MessageBox in der Bildschirmmitte erscheint, dürfte dem Anwender vertraut vorkommen.

    Als Owner legt man übrigens kein Control fest, sondern ein Formular. Üblicherweise, das aus dem die MessageBox aufgerufen wurde.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Samstag, 8. Mai 2010 11:17
    Beantworter
  • Hallo JoHom,

    Die System.Windows.Forms.MessageBox kapselt die Windows API-Funktion MessageBox() aus der user32.dll. Diese bietet leider keine eingebaute Funktionalität zum Zentrieren des Meldungs-Fensters. Der einfachste mir bekannte Weg eine Standard-MessageBox zu zentrieren, geht - wie schon Thorsten schrieb - über die Verwendung eines CBT-Hooks.

    s.a. How To Position a MsgBox Using a Windows Hook Procedure:
    http://support.microsoft.com/kb/180936/en-us

    Hier ist die C#-Portierung des MSDN-Beispiels aus dem o.g. Link:

    namespace CenteredMessageBox
    {
     using System;
     using System.Runtime.InteropServices;
     using System.Windows.Forms;
    
     public static class MessageBoxEx
     {
      private const int GWL_HINSTANCE = -0x6;
      private const int SWP_NOSIZE = 0x1;
      private const int SWP_NOZORDER = 0x4;
      private const int SWP_NOACTIVATE = 0x10;
      private const int HCBT_ACTIVATE = 0x5;
      private const int WH_CBT = 0x5;
    
      private static RECT rectMsgBox;
      private static RECT rectForm;
      private static int hook;
    
      private delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    
      public static DialogResult ShowCentered(Form parentForm, string message)
      {
       return ShowCentered(parentForm, message, String.Empty, MessageBoxButtons.OK, MessageBoxIcon.None);
      }
    
      public static DialogResult ShowCentered(Form parentForm, string message, string title)
      {
       return ShowCentered(parentForm, message, title, MessageBoxButtons.OK, MessageBoxIcon.None);
      }
    
      public static DialogResult ShowCentered(Form parentForm, string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
      {
       if (hook == 0)
       {
        rectForm = new RECT() { Bottom = parentForm.Bottom, Left = parentForm.Left, Right = parentForm.Right, Top = parentForm.Top };
        IntPtr instanceHandle = GetWindowLongPtr(parentForm.Handle, GWL_HINSTANCE);
        int threadId = AppDomain.GetCurrentThreadId();
        hook = SetWindowsHookEx(WH_CBT, WinProc1, instanceHandle, threadId);
       }
    
       return MessageBox.Show(parentForm, message, title, buttons, icon);
      }
    
      private static int WinProc1(int nCode, IntPtr wParam, IntPtr lParam)
      {
       if (nCode == HCBT_ACTIVATE)
       {
        HandleRef handle = new HandleRef(rectForm, wParam);
        if (GetWindowRect(handle, out rectMsgBox))
        {
         int x = (rectForm.Left + ((rectForm.Right - rectForm.Left) / 2)) - ((rectMsgBox.Right - rectMsgBox.Left) / 2);
         int y = (rectForm.Top + ((rectForm.Bottom - rectForm.Top) / 2)) - ((rectMsgBox.Bottom - rectMsgBox.Top) / 2);
    
         SetWindowPos(wParam, IntPtr.Zero, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
         UnhookWindowsHookEx(hook);
         hook = 0;
        }
       }
    
       return 0;
      }
    
      [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
      private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    
      [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
      private static extern bool UnhookWindowsHookEx(int idHook);
    
      [DllImport("user32.dll", EntryPoint = "GetWindowLong")] // EntryPoint="GetWindowLongPtr" on 64-bit
      private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
    
      [DllImport("user32.dll", SetLastError = true)]
      [return: MarshalAs(UnmanagedType.Bool)]
      private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      private static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
    
      [DllImport("kernel32.dll")]
      private static extern uint GetCurrentThreadId();
    
      [StructLayout(LayoutKind.Sequential)]
      private struct RECT
      {
       public int Left;
       public int Top;
       public int Right;
       public int Bottom;
      }
     }
    }
    

    Der Aufruf ist dann denkbar einfach:

    MessageBoxEx.ShowCentered(this, "Diese Meldung wird zentriert angezeigt.", "Test");

     

    Gruss
    Marcel

    Mittwoch, 12. Mai 2010 12:39
  • Hallo

    vielen Dank für eure Antworten. Es scheint damit wirklich keine einfache Möglichkeit der Positionierung einer Messagebox zu geben. Herrn Dörfler muss ich jedoch insoweit Wiedersprechen, dass es sicher nicht allen Anwender vertraut ist eine Messagebox in der Bildschirmmitte vorzufinden. Wenigstens die MFC positioniert die Box zentriert zur Anwendung und stellt damit einen direkten Bezug zu ihr her. Das ein Framework wie .Net das nicht standartmäßig bereitstellen kann, ist meiner Meinung nach sehr schade.  

    Nochmals vielen Dank
    JoHom

     

    Donnerstag, 13. Mai 2010 09:01