在我的 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 即可。但是,我想知道是否有更简单的方法来实现这一目标。
非常感谢您的支持/想法。
我找到了一种更简单的方法来做到这一点。我添加到一个助手类中
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);
}