分享一个可携带附加消息的增强消息框MessageBoxEx
--------------201507160917更新---------------
无意中发现标准消息框在Windows7是有声音的,只是在Windows server 2008(R2)无声,而我用的刚好是后者,所以误以为是MessageBeep API在所有NT6系统都不工作造成~汗,有人在stackoverflow也提过这问题。但我仍然决定使用PlaySound API,不做修改
将声音处理交给ProcessIcon方法负责。之前考虑松耦合,所以将MessageBoxIcon和声音分开处理,但其实声音就是根据前者而来,两者天然就是耦合的,分开处理多此一举
--------------201507091034更新---------------
首先感谢猿友E204在回复中的反馈。
解决双击【详细信息】按钮造成的Checked状态改变问题,办法是让ToggleButton忽略WM_LBUTTONDBLCLK消息
修正收起详细信息区逻辑,改为直接取用plAttachZone.Height。之前是取ExpandHeight,会造成视觉体验问题
--------------201507082014原文(已更新)---------------
适用于:.net 2.0+的Winform项目
样子:
有损录制+制图的原因不可能原样展示出真实效果,可至文章结尾下载Demo体验。
功能和特点:
- 相对父窗体居中
- 可附带附加消息。附加消息可以是string和Exception类型,【详细信息】按钮会根据是否传入附加信息显示和隐藏。传入Exception实例时,呈现的是exception.ToString(),也就是可能携带StackTrace信息,所以如果你只是想呈现异常文本,还是老实传入ex.Message
- 展开/收起附加信息时有动画效果。实用为王的你亦可设置EnableAnimate=false关闭动画效果
- 在Windows Server 2008 R2(未测试其它服务器系统)也有声音反馈。标准消息框在个人系统(XP/Win7等)是有声音的,但在srv08却没有。同时亦提供了EnableSound属性允许你关闭声音反馈
- 移除了标准MessageBox提供的IWin32Window、MessageBoxOptions和Help相关参数,原因是我用不到,懒得实现
- 可拖拉改变消息框尺寸,消息文本和附加文本会随窗体大小重排。这是标准消息框未提供的能力。改变尺寸分两种情况有不同的行为:①详细信息未展开时,改变的是主消息区大小;②详细信息展开时,改变的是详细信息区的大小
总体来说,此消息框比较适合用在需要反馈大量消息文本的场合,用标准消息框的话,文本太多可能会使消息框超出屏幕大小,比如codeproject.com上这位老兄举的例子,由于标准消息框不具备改变窗体大小的能力,将导致部分消息无法让用户看到。而就算没有超出屏幕,一下子让用户面对那么多消息文字,体验也不地道。使用本消息框就可以解决此类问题,比如可以将扼要信息显示在主消息区,将大量的明细消息(例如批量处理中的单项处理情况)、次要消息、异常信息等放置在详细信息区,由用户或IT支持人员自己去展开获取这些信息。同时,在没有附加消息的时候,你仍然可以像标准消息框一样使用它,所以,如果你跟我一样不会用到标准消息框的IWin32Window、MessageBoxOptions和Help相关参数的话,基本上你可以在整个项目中全程用此消息框替换掉标准消息框,别忘了相比标准消息框,它还具备了可缩放、相对父窗体居中等额外能力。总言之,你值得拥有。至于如果你担心性能问题,这个~我想这么说,我对自己的代码质量还是有点信心的。也希望能得大侠指出槽点,感激!
使用说明:
先看公开成员:
//静态属性 MessageBoxEx.EnableAnimate MessageBoxEx.EnableSound //静态方法 MessageBoxEx.Show(string, string, string) MessageBoxEx.Show(string, string, string, MessageBoxButtons) MessageBoxEx.Show(string, string, string, MessageBoxButtons, MessageBoxIcon) MessageBoxEx.Show(string, string, string, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton) MessageBoxEx.Show(string, string, Exception) MessageBoxEx.Show(string, string, Exception, MessageBoxButtons) MessageBoxEx.Show(string, string, Exception, MessageBoxButtons, MessageBoxIcon) MessageBoxEx.Show(string, string, Exception, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton)</div>
属性EnableAnimate和EnableSound上面提过,分别是用来启用/关闭动画、声音效果的,默认是都启用。俩属性影响范围是全局的,比如设置EnableAnimate = false后,之后弹出的MessageBoxEx都没有动画效果,直到重新设为true,EnableSound亦然。最佳实践是将它俩与用户偏好设置相关联,允许用户自主控制
方法则只有一个:Show(),从重载列表你大概都能知道如何使用。其中第3个参数就是附加消息,可接受string和Exception类的实例,其余参数的位置和意义与标准消息框一致。简要示例如下:
MessageBoxEx.Show("主消息", "标题", "附加消息", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); MessageBoxEx.Show("主消息", "标题", ex, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);</div>
前3个参数可以放心为null,内部有处理,后面的枚举你也null不了,如果传入无效枚举值,会抛异常
只有3个string参数的那个方法,后面俩参数是可选的。所以不讲究消息体验的你仍然可以这样使用:
MessageBoxEx.Show("阿斯顿发"); MessageBoxEx.Show("阿斯顿发", "士大夫");</div>
方案源码:
代码不少,原因自然是有的,有兴趣的童鞋请看后面的实现说明。另外,千万不要认为代码量跟性能有直接关系,有时候更多的代码恰恰是为了提升性能而存在,有时候则是为了健壮性。
using System; using System.ComponentModel; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace AhDung.WinForm { /// <summary> /// 可以携带详细信息的消息框 /// </summary> public static class MessageBoxEx { //异常消息文本 private const string InvalidButtonExString = "按钮参数不是有效的枚举项!"; private const string InvalidIconExString = "图标参数不是有效的枚举项!"; private const string InvalidDfButtonExString = "默认按钮参数不是有效的枚举项!"; /// <summary> /// 是否启用动画效果 /// </summary> public static bool EnableAnimate { get; set; } /// <summary> /// 是否启用声音反馈 /// </summary> public static bool EnableSound { get; set; } //静态构造 static MessageBoxEx() { //默认启用动画+声音 EnableAnimate = true; EnableSound = true; } #region 公开方法 /// <summary> /// 显示消息框 /// </summary> /// <param name="message">消息文本</param> /// <param name="caption">消息框标题</param> /// <param name="attachMessage">附加消息</param> public static DialogResult Show(string message, string caption = null, string attachMessage = null) { return ShowCore(message, caption, attachMessage, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /*下面这仨弄成重载而不是可选方法是为了避免不必要的参数检查*/ /// <summary> /// 显示消息框 /// </summary> /// <param name="message">消息文本</param> /// <param name="caption">消息框标题</param> /// <param name="attachMessage">附加消息</param> /// <param name="buttons">按钮组合</param> public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons) { if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); } return ShowCore(message, caption, attachMessage, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// <summary> /// 显示消息框 /// </summary> /// <param name="message">消息文本</param> /// <param na