最顶层WPF风格MessageBox

问题描述 投票:0回答:1

在我的 VSTO Excel Addin 应用程序中,当用户尝试关闭任何打开的工作簿时,我希望将 Systems.Window.MessageBox 显示为最顶层窗口 - 就像 Excel 在“移动或复制...”时尝试关闭工作簿时所做的那样” 显示小窗口。使用 Systems.Window.Forms.MessageBox 会更简单,但是我希望保留 Systems.Window.MessageBox 的“WPF 样式”。

我在stackoverflow上发现了这个问题https://stackoverflow.com/questions/16105097/why-isnt-messagebox-topmost所以我进一步扩展了这个代码 - 按照https://learn.microsoft.com/en- us/windows/win32/api/winuser/nf-winuser-messagebox。我没有包括对话框的模式和附加选项。它还存在一个问题:如果使用多屏幕设置,则即使 Excel 显示在另一个显示器上,MessageBox 也将显示在主显示器的最上方。这是助手类。

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;


namespace MyAddIn
{
    public class MessageBoxHelperClass
    {
        [DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = CharSet.Auto)]
        public static extern int MessageBoxUser32(IntPtr hWnd, string text, string caption, uint type);

        private const uint MB_TOPMOST = 0x00040000;

        private const uint MB_OK = 0x00000000;
        private const uint MB_OKCANCEL = 0x00000001;
        private const uint MB_YESNOCANCEL = 0x00000003;
        private const uint MB_YESNO = 0x00000004;

        private const uint MB_ICONERROR = 0x00000010;
        private const uint MB_ICONQUESTION = 0x00000020;
        private const uint MB_ICONEXCLAMATION = 0x00000030;
        private const uint MB_ICONINFORMATION = 0x00000040;

        private const uint MB_DEFBUTTON1 = 0x00000000;
        private const uint MB_DEFBUTTON2 = 0x00000100;
        private const uint MB_DEFBUTTON3 = 0x00000200;

        public static MessageBoxResult ShowMessageBox(string message, bool topMost = true, string title = null, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.None)
        {
            uint type = topMost ? MB_TOPMOST : 0;

            // Add button flags
            switch (buttons)
            {
                case MessageBoxButton.OK:
                    type |= MB_OK;
                    break;
                case MessageBoxButton.OKCancel:
                    type |= MB_OKCANCEL;
                    break;
                case MessageBoxButton.YesNoCancel:
                    type |= MB_YESNOCANCEL;
                    break;
                case MessageBoxButton.YesNo:
                    type |= MB_YESNO;
                    break;
            }

            // Add icon flags
            switch (icon)
            {
                case MessageBoxImage.Error:
                    type |= MB_ICONERROR;
                    break;
                case MessageBoxImage.Question:
                    type |= MB_ICONQUESTION;
                    break;
                case MessageBoxImage.Exclamation:
                    type |= MB_ICONEXCLAMATION;
                    break;
                case MessageBoxImage.Information:
                    type |= MB_ICONINFORMATION;
                    break;
            }

            // Add default button flags
            switch (defaultResult)
            {
                case MessageBoxResult.OK:
                    type |= MB_DEFBUTTON1;
                    break;
                case MessageBoxResult.Cancel:
                    if (buttons == MessageBoxButton.YesNoCancel)
                    {
                        type |= MB_DEFBUTTON2;
                    }
                    else
                    {
                        type |= MB_DEFBUTTON1;
                    }
                    break;
                case MessageBoxResult.Yes:
                    type |= MB_DEFBUTTON1;
                    break;
                case MessageBoxResult.No:
                    type |= MB_DEFBUTTON2;
                    break;
            }

            IntPtr hwnd = IntPtr.Zero;

            if (System.Windows.Application.Current != null && System.Windows.Application.Current.MainWindow != null)
            {
                WindowInteropHelper wih = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
                hwnd = wih.Handle;
            }

            int result = 0;

            if (topMost)
            {
                result = MessageBoxUser32(hwnd, message, title ?? string.Empty, type);
            }
            else
            {
                System.Windows.MessageBoxResult wpfResult = System.Windows.MessageBox.Show(message, title ?? string.Empty, buttons, icon);
                return ConvertWpfToCustomMessageBoxResult(wpfResult);
            }

            return ConvertWin32ToCustomMessageBoxResult(result, buttons);
        }

        private static MessageBoxResult ConvertWin32ToCustomMessageBoxResult(int win32Result, MessageBoxButton buttons)
        {
            switch (win32Result)
            {
                case 1: // IDOK
                    return MessageBoxResult.OK;
                case 2: // IDCANCEL
                    return MessageBoxResult.Cancel;
                case 6: // IDYES
                    return MessageBoxResult.Yes;
                case 7: // IDNO
                    return MessageBoxResult.No;
                default:
                    return MessageBoxResult.None;
            }
        }

        private static MessageBoxResult ConvertWpfToCustomMessageBoxResult(MessageBoxResult wpfResult)
        {
            switch (wpfResult)
            {
                case System.Windows.MessageBoxResult.OK:
                    return MessageBoxResult.OK;
                case System.Windows.MessageBoxResult.Cancel:
                    return MessageBoxResult.Cancel;
                case System.Windows.MessageBoxResult.Yes:
                    return MessageBoxResult.Yes;
                case System.Windows.MessageBoxResult.No:
                    return MessageBoxResult.No;
                default:
                    return MessageBoxResult.None;
            }
        }
    }
}

我有一个大部分有效的解决方案 - 只需弄清楚如何在正确的显示器上显示 MessageBox 即可。但是,我想知道是否有更简单的方法来实现这一目标。

非常感谢您的支持/想法。

excel wpf vsto messagebox topmost
1个回答
0
投票

我找到了一种更简单的方法来做到这一点。我添加到一个助手类中

private static System.Windows.Window activeWindow;

public static System.Windows.Window GetActiveWindow()
{
    return activeWindow;
}

public static void ShowDialog(System.Windows.Window window)
{
    activeWindow = window;
    window.ShowDialog();
    activeWindow = null;
}

public static void ResetActiveWindow()
{
    activeWindow = null;
}

所以当我创建 WPF 窗口时我会这样做

 MyWPFWindow myWPFWindow = new MyWPFWindow();
 HelperClass.ShowDialog(myWPFWindow);

 if (!importWPF.DialogResult.Equals(true))
 {
     
 }

然后我这样做

var activeWindow = HelperClass.GetActiveWindow();

string message = "Cannot quit Microsoft Excel.";
string caption = "Microsoft Excel";

if (activeWindow != null)
{
    MessageBox.Show(activeWindow, message, caption, MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
    MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Information);
}
© www.soinside.com 2019 - 2024. All rights reserved.