Подтвердить что ты не робот

Как заставить MessageBox.Show() появляться в середине моего приложения WPF?

У меня есть 700w x 300h WPF-приложение и его можно перетащить в любом месте на моем большом экране.

Когда мое приложение выполняет:

MessageBox.Show("Sorry, this function is not yet implemented.");

ящик для сообщений отображается в середине моего экрана, который может быть или даже не быть рядом с самим приложением.

Как я могу заставить MessageBox отображаться в середине моего приложения?

4b9b3361

Ответ 1

Если ваше приложение имеет несколько окон, вы можете использовать Application.Current.MainWindow:

MessageBox.Show(Application.Current.MainWindow, "Can't login with given names.", "Login Failure", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.Cancel);

Ответ 2

Здесь версия вспомогательного класса MessageBoxEx, размещенная в другом потоке, который использует окна сообщений стиля WPF (обратите внимание, что вам все равно нужно ссылаться на 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);
    }
}

Ответ 3

Это было здесь для Windows.Forms, но со следующим добавлением в ваш класс вы можете заставить его работать в WPF.

Вы должны добавить ссылку на System.Windows.Forms и System.Drawing для вышеприведенного класса и сделать следующее.

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

Затем вы можете вызвать MessageBoxEx с помощью:

MessageBoxEx.Show(this, "Message");

Он должен появиться в середине вашего окна.

Ответ 4

Другим подходом было бы создать собственное окно окна сообщения и установить местоположение запуска окна для владельца центра. Преимущество заключается в том, что вы можете легко создавать свои стили и настраивать, не зацепляясь.

Ответ 5

В дополнение к ответ Framnk

Эта часть не работает на нескольких экранах

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

здесь quickfix:

var allScreens = System.Windows.Forms.Screen.AllScreens;
ptStart.X = allScreens.All(a => a.WorkingArea.Left > ptStart.X) ? allScreens.Min(a => a.WorkingArea.Left) : ptStart.X;
ptStart.X = allScreens.All(a => a.WorkingArea.Right - width < ptStart.X) ? allScreens.Max(a => a.WorkingArea.Right) - width : ptStart.X;
ptStart.Y = allScreens.All(a => a.WorkingArea.Top > ptStart.Y) ? allScreens.Min(a => a.WorkingArea.Top) : ptStart.Y;
ptStart.Y = allScreens.All(a => a.WorkingArea.Bottom - height < ptStart.Y) ? allScreens.Max(a => a.WorkingArea.Bottom) - height : ptStart.Y;

Ответ 6

Если вы открыты для использования внешних библиотек, одним из вариантов является Xceed WPF Toolkit, который имеет MessageBox, который будет правильно центрироваться. Он также очень совместим с WPF в целом, например, он может быть стилизован из XAML.

https://github.com/xceedsoftware/wpftoolkit/wiki/MessageBox

использование

MessageBox имитирует поведение System.Windows.MessageBox. Вы используете похожий синтаксис для создания и отображения окна сообщения.

MessageBoxResult result =  Xceed.Wpf.Toolkit.MessageBox.Show("Hello world!", "Extended WPF ToolKit MessageBox", MessageBoxButton.OK, MessageBoxImage.Question);

MessageBoxResult result =  Xceed.Wpf.Toolkit.MessageBox.Show("Hello world!", "Extended WPF ToolKit MessageBox", MessageBoxButton.OK);

MessageBoxResult result =  Xceed.Wpf.Toolkit.MessageBox.Show("Hello world!", "Extended WPF ToolKit MessageBox");

MessageBoxResult result =  Xceed.Wpf.Toolkit.MessageBox.Show("Hello world!");

Центрирование в родительском окне выглядит автоматическим.