.Net下Winform程序让MessageBox.Show显示在父窗体中间

本文介绍了一个自定义MessageBoxEx类,该类允许MessageBox始终居中显示在其父窗口上,通过使用WinAPI函数实现。
下面的写法,默认是显示在屏幕的中间。
DialogResult dr = MessageBox.Show("是否要删除此数据?", "删除确认", MessageBoxButtons.OKCancel,MessageBoxIcon.Information,MessageBoxDefaultButton.Button2);

if (dr == DialogResult.Cancel)
{
    return;
}

要让MessageBoxEx.Show显示在父窗体中间,需要重新写个下面的类,调用WINAPI函数。

using System;
using System.Windows.Forms;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;


public class MessageBoxEx
{
    private static IWin32Window _owner;
    private static HookProc _hookProc;
    private static IntPtr _hHook;

    public static DialogResult Show(string text)
    {
        Initialize();
        return MessageBox.Show(text);
    }

    public static DialogResult Show(string text, string caption)
    {
        Initialize();
        return MessageBox.Show(text, caption);
    }

    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons);
    }

    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons, icon);
    }

    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons, icon, defButton);
    }

    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton, MessageBoxOptions options)
    {
        Initialize();
        return MessageBox.Show(text, caption, buttons, icon, defButton, options);
    }

    public static DialogResult Show(IWin32Window owner, string text)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text);
    }

    public static DialogResult Show(IWin32Window owner, string text, string caption)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text, caption);
    }

    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons);
    }

    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon);
    }

    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon, defButton);
    }

    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defButton, MessageBoxOptions options)
    {
        _owner = owner;
        Initialize();
        return MessageBox.Show(owner, text, caption, buttons, icon,
                               defButton, 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.Handle, ref recParent);

        Point ptCenter = new Point(0, 0);
        ptCenter.X = recParent.X + ((recParent.Width - recParent.X) / 2);
        ptCenter.Y = recParent.Y + ((recParent.Height - recParent.Y) / 2);

        Point ptStart = new 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);
    }
}
调用方式
DialogResult dr = MessageBoxEx.Show(this,"是否要删除此数据?", "删除确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2);

if (dr == DialogResult.Cancel)
{
    return;
}



<think>好的,用户现在想在.NET4.6中使用MaterialSkin来自定义WinFormMessageBox样式,并且解决之前遇到的lblMessage.Text未声明的问题。我需要先回顾之前的对话,确保这次回答能覆盖所有要点。首先,用户之前提到lblMessage.Text未声明的问题,我之前给出的解决方案是检查设计器是否添加了控件,命名是否正确,以及是否继承正确的控件类型。现在用户进一步希望将MaterialSkin应用到MessageBox上,所以需要结合这两个需求。用户参考了站内引用,其中提到让MessageBox显示父窗体中间,以及按钮和图标样式的使用。但用户的实际需求是自定义MessageBox的样式,而原生的MessageBox无法直接修改,所以需要创建自定义窗体来模拟MessageBox的行为。接下来,我需要分步骤说明如何创建自定义的MaterialMessageBox窗体,使用MaterialSkin控件替换原生控件,并确保正确声明和引用lblMessage。需要包括添加MaterialLabel控件、设置属性、初始化代码以及显示对话框的方法。 同时,要解决lblMessage.Text未声明的问题,必须确保设计器文件中正确生成了控件的声明和初始化,并且在代码中正确引用。可能需要指导用户检查Designer.cs文件,或者手动添加控件声明。 另外,用户可能遇到的常见问题包括控件未正确继承MaterialSkin的样式,或者事件处理不正确,比如关闭按钮的逻辑。需要提醒用户在主窗体中初始化MaterialSkinManager,以确保样式一致。最后,生成的相关问题需要围绕MaterialSkin的使用和自定义窗体展开,例如如何添加图标、处理长文本、动画效果等。确保问题与当前主题相关,帮助用户深入理解。</think>### 解决方案:在.NET 4.6中使用MaterialSkin自定义WinForm MessageBox样式 --- #### 一、问题分析 1. **原生MessageBox限制** - 原生`MessageBox`无法直接应用MaterialSkin样式 - 需要创建自定义窗体`MaterialMessageBox`来模拟标准对话框行为[^1] 2. **lblMessage.Text未声明问题** - 未正确声明`MaterialLabel`控件 - 设计器文件未正确生成控件初始化代码 --- #### 二、实现步骤 ##### 1. 创建自定义窗体类 ```csharp using MaterialSkin; using MaterialSkin.Controls; public partial class MaterialMessageBox : MaterialForm { // 声明MaterialLabel控件 private MaterialLabel lblMessage; private MaterialButton btnOK; private MaterialButton btnCancel; } ``` ##### 2. 设计器配置(MaterialMessageBox.Designer.cs) ```csharp private void InitializeComponent() { this.lblMessage = new MaterialSkin.Controls.MaterialLabel(); this.btnOK = new MaterialSkin.Controls.MaterialButton(); this.btnCancel = new MaterialSkin.Controls.MaterialButton(); // 标签配置 this.lblMessage.AutoSize = false; this.lblMessage.Depth = 0; this.lblMessage.Dock = DockStyle.Fill; this.lblMessage.Font = new Font("微软雅黑", 11F); this.lblMessage.Location = new Point(10, 80); this.lblMessage.Size = new Size(380, 120); // 按钮配置 this.btnOK.DialogResult = DialogResult.OK; this.btnCancel.DialogResult = DialogResult.Cancel; } ``` ##### 3. 构造函数与初始化 ```csharp public MaterialMessageBox(string text, string caption, MessageBoxButtons buttons) { InitializeComponent(); // 应用MaterialSkin主题 var materialSkinManager = MaterialSkinManager.Instance; materialSkinManager.AddFormToManage(this); materialSkinManager.Theme = MaterialSkinManager.Themes.LIGHT; // 设置控件属性 this.Text = caption; lblMessage.Text = text; // 确保控件已正确初始化 // 动态创建按钮布局 switch (buttons) { case MessageBoxButtons.OKCancel: btnOK.Text = "确定"; btnCancel.Text = "取消"; break; case MessageBoxButtons.YesNo: btnOK.Text = "是"; btnCancel.Text = "否"; break; } } ``` ##### 4. 显示对话框方法 ```csharp public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) { using (var dialog = new MaterialMessageBox(text, caption, buttons)) { // 居中显示 dialog.StartPosition = FormStartPosition.CenterParent; return dialog.ShowDialog(); } } ``` --- #### 三、关键问题解决:lblMessage.Text未声明 1. **设计器验证** - 确保`MaterialMessageBox.Designer.cs`包含: ```csharp private MaterialSkin.Controls.MaterialLabel lblMessage; // ... this.lblMessage = new MaterialSkin.Controls.MaterialLabel(); ``` 2. **代码执行顺序** - 在构造函数中先调用`InitializeComponent()`再操作控件属性: ```csharp public MaterialMessageBox() { InitializeComponent(); // 必须首先执行 lblMessage.Text = "初始化完成"; // 此时控件已存在 } ``` 3. **命名一致性检查** - 在窗体设计器属性面板确认: - 控件名称(Name)必须与代码中使用的名称完全一致 - 类型必须为`MaterialSkin.Controls.MaterialLabel` --- #### 四、使用示例 ```csharp // 在父窗体中调用 DialogResult result = MaterialMessageBox.Show( "确定要删除此文件吗?", "删除确认", MessageBoxButtons.OKCancel ); if (result == DialogResult.OK) { // 执行删除操作 } ``` --- #### 五、样式优化建议 1. **阴影效果** ```csharp this.Elevation = 24; // 设置窗体投影深度 ``` 2. **颜色主题** ```csharp materialSkinManager.ColorScheme = new ColorScheme( Primary.Blue600, Primary.Blue700, Primary.Blue500, Accent.Blue200, TextShade.WHITE ); ``` 3. **动画过渡** ```csharp this.ShowInTaskbar = false; this.Opacity = 0; Timer fadeTimer = new Timer { Interval = 10 }; fadeTimer.Tick += (s, e) => { this.Opacity += 0.1; }; fadeTimer.Start(); ``` --- #### 六、常见问题排查表 | 问题现象 | 解决方案 | |---------|----------| | 控件显示为灰色方块 | 检查是否调用了`MaterialSkinManager.AddFormToManage(this)` | | 文字显示不全 | 设置`lblMessage.AutoSize = false`并指定固定尺寸 | | 按钮点击无响应 | 确认`DialogResult`属性已正确设置 | | 窗体无法拖动 | 添加`MouseDown`事件处理逻辑[^1] | --- ### 相关问题 1. 如何为MaterialSkin对话框添加自定义图标? 2. 如何处理MaterialLabel长文本自动换行? 3. 如何实现MaterialForm的渐入渐出动画效果? 4. MaterialSkin控件如何与Windows原生API交互?
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值