How to get MessageBox.Show() to pop up in the middle of my WPF application?

Here's a version of the MessageBoxEx helper class posted in the other thread that uses WPF style message boxes (Note that you still need to reference System.Drawing):

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Drawing;

public class MessageBoxEx
{
    private static IntPtr _owner;
    private static HookProc _hookProc;
    private static IntPtr _hHook;

    public static MessageBoxResult Show(string text)
    {
        Initialize();
        return MessageBox.Show(text);
    }

    public static MessageBoxResult Show(string text, string caption)
    {
        Initialize();
        return MessageBox.Show(text, caption);
    }

    public static MessageBoxResult Show(string text, string caption, MessageBoxButton buttons)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons);
    }

    public static MessageBoxResult Show(string text, string caption, MessageBoxButton buttons, MessageBoxImage icon)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons, icon);
    }

    public static MessageBoxResult Show(string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defResult)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons, icon, defResult);
    }

    public static MessageBoxResult Show(string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defResult, MessageBoxOptions options)
    {
        Initialize();            
        return MessageBox.Show(text, caption, buttons, icon, defResult, options);
    }

    public static MessageBoxResult Show(Window owner, string text)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text);
    }

    public static MessageBoxResult Show(Window owner, string text, string caption)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text, caption);
    }

    public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons);
    }

    public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon);
    }

    public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defResult)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon, defResult);
    }

    public static MessageBoxResult Show(Window owner, string text, string caption, MessageBoxButton buttons, MessageBoxImage icon, MessageBoxResult defResult, MessageBoxOptions options)
    {
        _owner = new WindowInteropHelper(owner).Handle;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon,
                                defResult, options);
    }

    public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    public delegate void TimerProc(IntPtr hWnd, uint uMsg, UIntPtr nIDEvent, uint dwTime);

    public const int WH_CALLWNDPROCRET = 12;

    public enum CbtHookAction : int
    {
        HCBT_MOVESIZE = 0,
        HCBT_MINMAX = 1,
        HCBT_QS = 2,
        HCBT_CREATEWND = 3,
        HCBT_DESTROYWND = 4,
        HCBT_ACTIVATE = 5,
        HCBT_CLICKSKIPPED = 6,
        HCBT_KEYSKIPPED = 7,
        HCBT_SYSCOMMAND = 8,
        HCBT_SETFOCUS = 9
    }

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle lpRect);

    [DllImport("user32.dll")]
    private static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

    [DllImport("User32.dll")]
    public static extern UIntPtr SetTimer(IntPtr hWnd, UIntPtr nIDEvent, uint uElapse, TimerProc lpTimerFunc);

    [DllImport("User32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

    [DllImport("user32.dll")]
    public static extern int UnhookWindowsHookEx(IntPtr idHook);

    [DllImport("user32.dll")]
    public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern int GetWindowTextLength(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int maxLength);

    [DllImport("user32.dll")]
    public static extern int EndDialog(IntPtr hDlg, IntPtr nResult);

    [StructLayout(LayoutKind.Sequential)]
    public struct CWPRETSTRUCT
    {
        public IntPtr lResult;
        public IntPtr lParam;
        public IntPtr wParam;
        public uint message;
        public IntPtr hwnd;
    } ;

    static MessageBoxEx()
    {
        _hookProc = new HookProc(MessageBoxHookProc);
        _hHook = IntPtr.Zero;
    }

    private static void Initialize()
    {
        if (_hHook != IntPtr.Zero)
        {
            throw new NotSupportedException("multiple calls are not supported");
        }

        if (_owner != null)
        {
            _hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, _hookProc, IntPtr.Zero, AppDomain.GetCurrentThreadId());
        }
    }

    private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode < 0)
        {
            return CallNextHookEx(_hHook, nCode, wParam, lParam);
        }

        CWPRETSTRUCT msg = (CWPRETSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPRETSTRUCT));
        IntPtr hook = _hHook;

        if (msg.message == (int)CbtHookAction.HCBT_ACTIVATE)
        {
            try
            {
                CenterWindow(msg.hwnd);
            }
            finally
            {
                UnhookWindowsHookEx(_hHook);
                _hHook = IntPtr.Zero;
            }
        }

        return CallNextHookEx(hook, nCode, wParam, lParam);
    }

    private static void CenterWindow(IntPtr hChildWnd)
    {
        Rectangle recChild = new Rectangle(0, 0, 0, 0);
        bool success = GetWindowRect(hChildWnd, ref recChild);

        int width = recChild.Width - recChild.X;
        int height = recChild.Height - recChild.Y;

        Rectangle recParent = new Rectangle(0, 0, 0, 0);
        success = GetWindowRect(_owner, ref recParent);

        System.Drawing.Point ptCenter = new System.Drawing.Point(0, 0);
        ptCenter.X = recParent.X + ((recParent.Width - recParent.X) / 2);
        ptCenter.Y = recParent.Y + ((recParent.Height - recParent.Y) / 2);


        System.Drawing.Point ptStart = new System.Drawing.Point(0, 0);
        ptStart.X = (ptCenter.X - (width / 2));
        ptStart.Y = (ptCenter.Y - (height / 2));

        ptStart.X = (ptStart.X < 0) ? 0 : ptStart.X;
        ptStart.Y = (ptStart.Y < 0) ? 0 : ptStart.Y;

        int result = MoveWindow(hChildWnd, ptStart.X, ptStart.Y, width,
                                height, false);
    }
}

This was answered here for Windows.Forms but with the following added to your class, you can get it to work in WPF.

You have to add a reference to System.Windows.Forms & System.Drawing for the class above to work and to do the following.

public partial class YourWPFWindow : Window, System.Windows.Forms.IWin32Window
{
    public IntPtr Handle
    {
        get { return new WindowInteropHelper(this).Handle; }
    }
}

Then you can call MessageBoxEx with:

MessageBoxEx.Show(this, "Message");

It should show up in the middle of your window.

Tags:

Wpf