如何让MessageBox.Show()在我的WPF应用程序中间弹出?

2o7dmzc5  于 2023-05-30  发布在  其他
关注(0)|答案(6)|浏览(231)

我有一个700W x 300H的WPF应用程序,可以将它拖到我的大屏幕上的任何地方。
当我的应用程序执行时:

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

消息框出现在我的 * 屏幕 * 的中间,它可能甚至可能不靠近应用程序本身。
我怎样才能让我的MessageBox出现在我的 * 应用程序 * 的中间?

j5fpnvbx

j5fpnvbx1#

下面是在使用WPF样式消息框的另一个线程中发布的MessageBoxEx帮助器类的一个版本(注意,您仍然需要引用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);
    }
}
kt06eoxx

kt06eoxx2#

这是answered here for 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");

它应该出现在你的窗口中间。

t9eec4r0

t9eec4r03#

另一种方法是创建自己的消息框窗口,并将窗口的启动位置设置为centerowner。优点是你可以很容易地有你的风格和定制,没有挂钩。

zzoitvuj

zzoitvuj4#

如果您愿意使用外部库,一个选择是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!");

父窗口居中显示为自动。

fbcarpbf

fbcarpbf5#

除了Framnk's answer
此部分在多个屏幕上不起作用

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

这里有一个快速解决方法:

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

tf7tbtn26#

如果您的应用有多个窗口,您可能需要使用Application.Current.MainWindow

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

相关问题