MessageBox.Show()

9

我希望在父窗体的中心显示我的消息框。如果我移动了窗体并显示消息框,它总是显示在桌面的中心。我希望它能够随着窗体一起出现。 你能给我一些技巧和建议吗?


可能是Winforms-如何使MessageBox出现在MainForm的中心?的重复问题。 - StayOnTarget
5个回答

3
最好的方法是使用窗口钩子并自己居中消息框。有一篇完美的文章展示了这种用法。
你可以在这里找到它: http://www.codeproject.com/KB/dialog/CenterDialog.aspx 你也可以在不深入了解其实际工作原理的情况下,在应用程序中使用该类。

这篇文章很棒。只是在应用到我的应用程序之前需要理解它。谢谢。有没有更简单的方法?嘿.. - Jepe d Hepe
1
最简单的方法是自己创建一个新的MessageBox窗体。这样可以根据您的喜好进行设计,看起来就像您想要的那样。此外,您还可以添加任何您喜欢的功能。 - Yogesh

2

我基于某个Windows Forms类制作了这个类。

将该类添加到您的WPF项目中,并像下面这样将“this”作为参数提供给辅助方法:

  MessageBoxHelper.PrepToCenterMessageBoxOnForm(this)" 

然后显示消息框:

MessageBox.Show("Hello there!");


/// <summary>
/// This class makes it possible to center a MessageBox over the parent dialog.
/// Usage example:
///         MessageBoxHelper.PrepToCenterMessageBoxOnForm(this);
///         MessageBox.Show("Hello there!);
/// </summary>
public static class MessageBoxHelper
{
    public static void PrepToCenterMessageBoxOnForm(Window window)
    {
        MessageBoxCenterHelper helper = new MessageBoxCenterHelper();
        helper.Prep(window);
    }

    private class MessageBoxCenterHelper
    {
        private int messageHook;
        private IntPtr parentFormHandle;

        public void Prep(Window window)
        {
            NativeMethods.CenterMessageCallBackDelegate callBackDelegate = new NativeMethods.CenterMessageCallBackDelegate(CenterMessageCallBack);
            GCHandle.Alloc(callBackDelegate);
            parentFormHandle = new WindowInteropHelper(window).Handle;
            messageHook = NativeMethods.SetWindowsHookEx(5, callBackDelegate, new IntPtr(NativeMethods.GetWindowLong(parentFormHandle, -6)), NativeMethods.GetCurrentThreadId()).ToInt32();
        }

        private int CenterMessageCallBack(int message, int wParam, int lParam)
        {
            NativeMethods.RECT formRect;
            NativeMethods.RECT messageBoxRect;
            int xPos;
            int yPos;

            if (message == 5)
            {
                NativeMethods.GetWindowRect(parentFormHandle, out formRect);
                NativeMethods.GetWindowRect(new IntPtr(wParam), out messageBoxRect);

                xPos = (int)((formRect.Left + (formRect.Right - formRect.Left) / 2) - ((messageBoxRect.Right - messageBoxRect.Left) / 2));
                yPos = (int)((formRect.Top + (formRect.Bottom - formRect.Top) / 2) - ((messageBoxRect.Bottom - messageBoxRect.Top) / 2));

                NativeMethods.SetWindowPos(wParam, 0, xPos, yPos, 0, 0, 0x1 | 0x4 | 0x10);
                NativeMethods.UnhookWindowsHookEx(messageHook);
            }

            return 0;
        }
    }

    private static class NativeMethods
    {
        internal struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        internal delegate int CenterMessageCallBackDelegate(int message, int wParam, int lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool UnhookWindowsHookEx(int hhk);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("kernel32.dll")]
        internal static extern int GetCurrentThreadId();

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern IntPtr SetWindowsHookEx(int hook, CenterMessageCallBackDelegate callback, IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    }
}

好的想法。但请注意你的措辞:“偷”是一个严厉的表达。我明确说了“在其他地方找到”,但你对归属权是完全正确的。 - AH.
1
不,原始代码并不来自您添加的链接。它来自Jason Carr:http://www.jasoncarr.com/technology/centering-a-message-box-on-the-active-window-in-csharp。我只是修改它以在WPF中运行。感谢Jason。 - AH.
哎呀,没看到你添加了那个链接 :-) - AH.
你应该创建一个变量来存储GCHandle.Alloc的结果,并在Callback Hook中调用GCHandle.Free(),然后再调用UnhookWindowsHookEx。 - Alan

1

将消息框窗口的所有者设置为您的窗口(使用.Show()的第一个参数),而不是不设置所有者。

请参见此处进行参考。


1
你能给我一些例子吗? 我已经尝试过这个:IWin32Window win = this; MessageBox.Show(win,"TESTING");然而,结果相同。消息框仍然弹出在桌面的中央。 - Jepe d Hepe
我想这取决于this是什么。恐怕我的经验仅限于本地Win32 MessageBox()函数,它有点不同,在我意识到你正在使用WinForms之前,我已经回答了一半。因此,我修改了我的答案以适应我在参考文献中找到的内容,但我可能仍然缺少一些细节。 :) - Greg Hewgill
1
将窗口句柄传递给MessageBox函数并不会在父窗口的中心显示消息框。这只是为了使消息框与父窗口一起最小化/最大化,并没有特定的任务图标用于消息框窗口。 - Yogesh
你能给我一个在父窗口中心显示消息框的例子吗? - Jepe d Hepe
@Yogesh:有趣,也许WinForms MessageBox没有使用Win32 MessageBox函数实现。 - Greg Hewgill

0

这里有一个非常易于使用的解决方案,而且它完美地工作:

步骤:

  1. 将该类复制并粘贴到您的项目中。我没有进行任何编辑就使用了它。
  2. 要使用修改后的MessageBox,在您的项目中使用以下代码行:

(在UserControlForm内部)

MessageBoxEx.Show(this, "Please fix the validation errors before saving.", "Validation Errors");

0

我以前在C#中做过这个。这是我记得的。

定义一个类:

public class IWindowWrapper : System.Windows.Forms.IWin32Window
{
    public IWindowWrapper(IntPtr handle)
    {
        this.Handle= handle;
    }

    public IntPtr Handle
    {
        get; 
        set;
    }
}

根据 MessageBox 定义一个类。基于 MessageBox 创建一个新的 Show 方法:

public string Show(IWin32Window owner)
{
   if(owner == null)
   {
    this.ShowDialog();
   }
   else
   {
      //parentWindow.
      this.StartPosition = FormStartPosition.CenterParent;
      this.ShowDialog(owner);
   }

}

在您的调用代码中(这里假设为Winform,并且MsgBox基于新的消息框类),调用新的Show方法并在Show上传递一个IWindowWrapper实例,例如。
msgBox.Show(new IWindowWrapper(this.Handle))

是的,例如:public class MyMessageBox : MessageBox ... 等等。 - ChrisBD
你不必使用C#来完成这个任务,但那是我用的语言。你在用什么编程语言呢? - ChrisBD
第二个代码。我会继承一个MessageBox吗?还是只是创建一个与MessageBox相同样式的窗体?如果我继承MessageBox,则this.ShowDialog()不可用。 - Jepe d Hepe
我正在使用C#。我认为这对我来说不可能。有人可以帮忙吗? - Jepe d Hepe
2
@ChrisBD:你打算如何继承一个MessageBox?能给个例子吗? - Yogesh
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接