C# wpf 自定义替换系统的MessageBox

WPF 自定义MessageBox系列

第一节 简单MessageBox
第二节 倒计时MessageBox
第三节 自定义按钮的MessageBox
第四节 界面操作分离的MessageBox
第五节 替换系统的MessageBox(本节)



前言

在上一篇《C# wpf 实现自定义界面操作分离的MessageBox》中我们得到了一个完整的MessageBox功能逻辑,将功能逻辑进行拓展,程序启动的时候,hook系统的MessageBox,变成调用自己的MessageBox。那我们只需要定义一个自己的MessageBox界面,绑定必要的属性,即可直接替换系统的MessageBox,或者说可以修改系统MessageBox的样式。


一、如何替换?

1、自定义MessageBox界面

《C# wpf 实现自定义界面操作分离的MessageBox》中我们定义一个DataContext对象,我们只需要定义一个自己需要MessageBox界面样式,然后绑定如下属性即可。

/// <summary>
/// 消息框的标题
/// </summary>
public string Title{get;get;}
/// <summary>
/// 消息框的文本内容
/// </summary>
public string Context{get;get;}
/// <summary>
/// Yes按钮的文本
/// </summary>
public string YesText{get;get;}
/// <summary>
/// No按钮的文本
/// </summary>
public string NoText{get;get;}
/// <summary>
/// Yes选项剩余时间(非系统MessageBox必须)
/// </summary>
public TimeSpan? YesLeftTime{get;get;}
/// <summary>
/// No选项剩余时间(非系统MessageBox必须)
/// </summary>
public TimeSpan? NoLeftTime{get;get;}
/// <summary>
/// No按钮命令
/// </summary>
public ICommand NoCommand{get;get;}
/// <summary>
/// Yes按钮命令
/// </summary>
public ICommand YesCommand{get;get;}
/// <summary>
///Cancel按钮命令
/// </summary>
public ICommand CancelCommand{get;get;}

2、使用钩子

使用钩子钩系统函数的方法不少,这里不提供具体方法。基本目的就是使得程序对MessageBox的调用,都进入自己的钩子函数中。其实查看源码就知道wpf的MessageBox底层调用了MessageBoxW,所以我们只需要将MessageBoxW方法钩掉。

3、替换逻辑

在钩子过程中使用自己的显示逻辑。Windows的MessageBox类型有很多,如果全部都制作相应的界面其实会比较复杂。但是在wpf中的MessageBox只提供了4种样式的MessageBox。所以在wpf中我们只需要实现这种样式即可。

namespace System.Windows
{
    //
    // 摘要:
    //     指定在消息框显示的按钮。 使用作为参数的 Overload:System.Windows.MessageBox.Show 方法。
    public enum MessageBoxButton
    {
        //
        // 摘要:
        //     该消息框显示 确定 按钮。
        OK = 0,
        //
        // 摘要:
        //     该消息框显示 确定 和 取消 按钮。
        OKCancel = 1,
        //
        // 摘要:
        //     该消息框显示 是, ,否, ,和 取消 按钮。
        YesNoCancel = 3,
        //
        // 摘要:
        //     该消息框显示 是 和 否 按钮。
        YesNo = 4
    }
}

这4种样式在WinApi中对应:

#define MB_OK                       0x00000000L
#define MB_OKCANCEL                 0x00000001L
#define MB_YESNOCANCEL              0x00000003L
#define MB_YESNO                    0x00000004L

所以在钩子过程中我们实现相应的Switch即可,下面是基于《C# wpf 实现自定义界面操作分离的MessageBox》代码的示例

Int32 ret = 0;
MessageBoxResult mr = null;
switch (uType)
{
    case 0:// MB_OK
        MessageBoxHelper.ShowDialog<T>(lpCaption, lpText, "确定");
        isHandled = true;
        ret = 1;//IDOK
        break;
    case 1:// MB_OKCANCEL                       
        mr= MessageBoxHelper.ShowDialog<T>(lpCaption, lpText, "确定", true);
        isHandled = true;
        if (mr.Button == MessageBoxResultButton.Yes)
        {
            ret = 1;//IDOK            
        }
        else if (mr.Button == MessageBoxResultButton.Cancel)
        {
            ret = 2;//IDCANCEL
        }
        break;
    case 3:// MB_YESNOCANCEL
        mr = MessageBoxHelper.ShowDialog<T>(lpCaption, lpText, "是", "否", true);
        isHandled = true;
        if (mr.Button == MessageBoxResultButton.Yes)
        {
            ret = 6;//IDYES               
        }
        else if (mr.Button == MessageBoxResultButton.No)
        {
            ret = 7;//IDNO
        }
        else if (mr.Button == MessageBoxResultButton.Cancel)
        {
            ret = 2;//IDCANCEL
        }
        break;
    case 4:// MB_YESNO
        mr = MessageBoxHelper.ShowDialog<T>(lpCaption, lpText, "是", "否");
        isHandled = true;
        if (mr.Button == MessageBoxResultButton.Yes)
        {
            ret = 6;//IDYES               
        }
        else if (mr.Button == MessageBoxResultButton.No)
        {
            ret = 7;//IDNO
        }
        break;
}    
return ret;

二、代码

笔者使用自己的钩子实现的代码。注意:下面资源的钩子写在了dll中不可见,且只能钩MessageBoxA和MessageBoxW,如果不符合自己的要求可以在《C# wpf 实现自定义界面操作分离的MessageBox》基础上自己实现一套钩子。
完整代码:
https://download.csdn.net/download/u013113678/34215409
替换MessageBox接口方法原型定义如下:

/// <summary>
/// 钩子过程委托
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="lpText">内容</param>
/// <param name="lpCaption">标题</param>
/// <param name="uType">消息框类型</param>
/// <param name="isHandled">是否拦截</param>
/// <returns>结果</returns>
public delegate Int32 MessageBoxHandleHandler(IntPtr hWnd, string lpText, string lpCaption, UInt32 uType, ref bool isHandled);
/// <summary>
/// 替换系统的MessageBox
/// </summary>
/// <param name="messageBoxHandleHandler">钩子过程</param>
public static void HookSystemMessageBox(MessageBoxHandleHandler messageBoxHandleHandler)
/// <summary>
/// 替换系统的MessageBox
/// </summary>
/// <typeparam name="T">用于替换的绑定MessageBoxDataContext属性的窗口类型</typeparam>
public static void HookSystemMessageBox<T>() where T : Window, new()

三、示例

使用自定义的MessageBox,下列代码中的MyMessageBox是自定义的。

//调用系统MessageBox显示消息
System.Windows.MessageBox.Show("内容","标题");
System.Windows.MessageBox.Show("内容", "标题",MessageBoxButton.YesNo);
//替换系统MessageBox
MessageBoxHelper.HookSystemMessageBox<MyMessageBox>();
//调用系统MessageBox显示消息
System.Windows.MessageBox.Show("内容","标题");
System.Windows.MessageBox.Show("内容", "标题",MessageBoxButton.YesNo);
//还原系统MessageBox
MessageBoxHelper.UnHookSystemMessageBox();
//调用系统MessageBox显示消息
System.Windows.MessageBox.Show("内容","标题");
System.Windows.MessageBox.Show("内容", "标题",MessageBoxButton.YesNo);

显示效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


总结

替换系统MessageBox属于一种切面编程技巧,方便于对旧项目的改造,尤其是涉及到频繁调用的代码,如果手动修改无疑是工作量巨大的,使用切面技巧可以很大程度的避免麻烦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeOfCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值