自定义功能的 MessageBox
一个如我们所愿的消息框。
引言
在开发程序时,我们经常需要使用 MessageBox
,它是与用户沟通的非常有用的工具。有时,我们希望 MessageBox
看起来像我们应用程序的一部分,或者与应用程序的主题相匹配,但这可能并不总是可行的。例如,我们在应用程序中将 LightSkyBlue
用作所有窗体的背景色,但当我们显示 MessageBox
时,它的样式始终是相同的。在这种组合中,MessageBox
会显得很奇怪。换句话说,我们对 MessageBox
控件没有完全的控制权。那么,为什么我们不制作一个我们想要的消息框,这样我们就可以完全控制它呢?
我浪费了很多宝贵的时间来寻找解决方案,但从未找到。于是,我计划自己做一个。经过大量的研发,我终于做到了。现在,我认为我应该与遇到相同问题的人分享我的解决方案。在本文的最后,读者将拥有一个自定义的 MessageBox
,并且可以对其进行完全控制。
设计
创建一个新项目,命名为“Custom Featured MessageBox”,打开其属性,并将“Output Type”设置为“Class Library”(因为 Class Library 输出是一个 DLL,可以轻松地添加到任何项目中)。在同一个解决方案中添加一个新项目,命名为“Test”,右键单击它,然后选择“Set as StartUp Project”。现在,回到“Custom Featured MessageBox”项目。
我们将需要
- 一个 Windows 窗体
- 一个
PictureBox
,用于显示图标 - 一个
TextBox
,用于显示文本(这里不能使用Label
,因为我们需要计算行数) - 三个
Button
s,用于对话框结果 - 三个
Panel
s,用于将所有控件放置在正确的位置和大小
设置控件属性如下
Form:
Name: XMessageBox
ControlBox: False
FormBorderStyle: FixedSingle
Max.Box: False
Min.Box: False
Padding: 10, 10, 10, 0
ShowIcon: False
ShowInTaskbar: False
Size: 262, 104
StartPosition: CenterScreen
TextBox:
BackColor: Control
BorderStyle: None
Dock: Fill
MaxLength: 0 (i.e. Max Length)
Multiline: True
ReadOnly: True
TabStop: False
TextAlign: Center
Panels:
Panel 1:
Name: leftPanel
Dock: Left
Visible: False
Controls:
PictureBox
Panel 2:
Name: bottomPanel
Dock: Bottom
Controls:
Panel 3
Panel 3 :
Name: bottomInnerPanel
Location: 0, 0
Size: 236, 30
Controls:
Button 1
Button 2
Button 3
PictureBox:
BackgroundImageLayout: Stretch
Location: 0, 0
Size: 32, 32
Button 1:
Location: 0, 3
Visible: False
Button 2:
Location: 81, 3
Visible: False
Button 3:
Location: 162, 3
Visible: False
做得好!现在,它看起来会像这样
使用代码
首先,创建两个类型为 int
的 const
成员变量。
const int minWidth = 262;
const int maxWidth = 600;
然后,我们需要创建两个 enum
s,XMessageBoxButtons
和 XMessageBoxIcon
,并带有 public
修饰符
public enum XMessageBoxButtons
{ OK, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel, }
public enum XMessageBoxIcon
{ Error, Question, Warning, Information, }
在此之后,创建两个方法 SetButtons
和 SetIcon
,分别用于设置按钮和图标
void SetButtons(XMessageBoxButtons buttons)
{
if (buttons == XMessageBoxButtons.OK)
{
button2.Visible = true;
button2.Text = "OK";
button2.DialogResult = DialogResult.OK;
ControlBox = true;
}
else if (buttons == XMessageBoxButtons.AbortRetryIgnore)
{
button1.Visible = true;
button1.Text = "Abort";
button1.DialogResult = DialogResult.Abort;
button2.Visible = true;
button2.Text = "Retry";
button2.DialogResult = DialogResult.Retry;
button3.Visible = true;
button3.Text = "Ignore";
button3.DialogResult = DialogResult.Ignore;
if (this.Width < minWidth)
this.Width = minWidth;
}
else if (buttons == XMessageBoxButtons.RetryCancel)
{
button1.Visible = true;
button1.Text = "Retry";
button1.DialogResult = DialogResult.Retry;
button1.Location = new Point(41, 3);
button2.Visible = true;
button2.Text = "Cancel";
button2.DialogResult = DialogResult.Cancel;
button2.Location = new Point(122, 3);
if (this.Width < minWidth)
this.Width = minWidth;
}
else if (buttons == XMessageBoxButtons.YesNo)
{
button1.Visible = true;
button1.Text = "Yes";
button1.DialogResult = DialogResult.Yes;
button1.Location = new Point(41, 3);
button2.Visible = true;
button2.Text = "No";
button2.DialogResult = DialogResult.No;
button2.Location = new Point(122, 3);
if (this.Width < minWidth)
this.Width = minWidth;
}
else if (buttons == XMessageBoxButtons.YesNoCancel)
{
button1.Visible = true;
button1.DialogResult = DialogResult.Yes;
button1.Text = "Yes";
button2.Visible = true;
button2.DialogResult = DialogResult.No;
button2.Text = "No";
button3.Visible = true;
button3.DialogResult = DialogResult.Cancel;
button3.Text = "Cancel";
if (this.Width < minWidth)
this.Width = minWidth;
}
}
void SetIcon(XMessageBoxIcon icon)
{
if (this.Height < 104)
this.Height = 104;
if (this.Width <= 600)
this.Width += 55;
leftPanel.Visible = true;
if (icon == XMessageBoxIcon.Information)
pictureBox1.BackgroundImage =
Custom_Featured_MessageBox.Properties.Resources.Information;
// Images have been added to Resources
else if (icon == XMessageBoxIcon.Warning)
pictureBox1.BackgroundImage =
Custom_Featured_MessageBox.Properties.Resources.Warning;
else if (icon == XMessageBoxIcon.Error)
pictureBox1.BackgroundImage =
Custom_Featured_MessageBox.Properties.Resources.Error;
else if (icon == XMessageBoxIcon.Question)
pictureBox1.BackgroundImage =
Custom_Featured_MessageBox.Properties.Resources.QuestionMark;
}
现在,我们应该创建一个方法来设置整个消息框。将其命名为 XmessageBox
,并带有七个参数
void XmessageBox(string text, string title, Size size, Font font,
Color backColor, Color foreColor, bool customSize)
{}
接下来,在其中编写代码,以便在调用时可以设置消息框
int width;
int height;
this.Text = title;
TextBox1.Text = text;
this.Font = font;
this.BackColor = backColor;
this.ForeColor = foreColor;
Graphics g = this.CreateGraphics(); // Initiating
SizeF textSize = g.MeasureString(text, font);
g.Dispose();
//|==================================================//
//|------------ //
//|CALCULATIONS //
//|------------ //
//|15, adjustment //
//|==================================================//
if (textSize.Width <= maxWidth)
width = (int)textSize.Width + 15;
else
width = maxWidth;
//|==================================================//
//|------------ //
//|CALCULATIONS //
//|------------ //
//|30 + 10 = 40, panal height + form's top padding //
//|40, adjustment //
//|==================================================//
height = (TextBox1.Lines.Length * TextBox1.Font.Height) + 40 + 40;
if (customSize == true) // set size only when customSize is true
this.Size = size;
else
this.Size = new Size(width, height);
完成后,选择窗体 (XMessageBox
),双击 Resize
事件,并编写这两行,以将所有对话框按钮置于窗体中央。
int x = (bottomPanel.Width - bottomInnerPanel.Width) / 2;
bottomInnerPanel.Location = new Point(x, bottomInnerPanel.Location.Y); // Y will same
另外,双击 BackColorChanged
和 ForeColorChanged
事件,以便在窗体颜色更改时设置 Textbox1
的颜色。
private void XMessageBox_ForeColorChanged(object sender, EventArgs e)
{
TextBox1.ForeColor = this.ForeColor;
}
private void XMessageBox_BackColorChanged(object sender, EventArgs e)
{
TextBox1.BackColor = this.BackColor;
}
创建一个 static
方法来显示 XMessageBox
(因为 static
方法可以在不创建实例的情况下调用)。将其命名为 show
,带有一个参数和一个 DialogResult
返回类型。
public static DialogResult show(string text)
{}
在此编写代码
XMessageBox f = new XMessageBox();
f.XmessageBox(text, "", f.Size, f.Font, f.BackColor, f.ForeColor, false);
f.SetButtons(XMessageBoxButtons.OK); // if button is not specified, then set OK
return f.ShowDialog();
在此代码中,我们创建了 XMessageBox
的一个实例并调用了它的一些必需方法。我们在此处未调用 SetIcon
,因为此 static
方法仅显示一个简单的消息框。
接下来,添加十二个更多方法来重载此方法
public static DialogResult show(string text, string title)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, f.BackColor, f.ForeColor, false);
f.SetButtons(XMessageBoxButtons.OK); // if button is not specified
return f.ShowDialog();
}
public static
DialogResult show(string text, string title, XMessageBoxButtons buttons)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, f.BackColor, f.ForeColor, false);
f.SetButtons(buttons);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
XMessageBoxButtons buttons, XMessageBoxIcon icon)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, f.BackColor, f.ForeColor, false);
f.SetButtons(buttons);
f.SetIcon(icon);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
XMessageBoxButtons buttons, Size size)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, f.Font, f.BackColor, f.ForeColor, true);
f.SetButtons(buttons);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
XMessageBoxButtons buttons, XMessageBoxIcon icon, Size size)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, f.Font, f.BackColor, f.ForeColor, true);
f.SetButtons(buttons);
f.SetIcon(icon);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
XMessageBoxButtons buttons, Size size, Font font)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, font, f.BackColor, f.ForeColor, true);
f.SetButtons(buttons);
return f.ShowDialog();
}
public static DialogResult show(string text, string title, XMessageBoxButtons buttons,
XMessageBoxIcon icon, Size size, Font font)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, font, f.BackColor, f.ForeColor, true);
f.SetButtons(buttons);
f.SetIcon(icon);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
Color backColor, Color foreColor)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, backColor, foreColor, false);
f.SetButtons(XMessageBoxButtons.OK);
return f.ShowDialog();
}
public static DialogResult show(string text, string title,
Color backColor, Color foreColor, XMessageBoxButtons buttons)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, backColor, foreColor, false);
f.SetButtons(buttons);
return f.ShowDialog();
}
public static DialogResult show(string text, string title, Color backColor,
Color foreColor, XMessageBoxButtons buttons, XMessageBoxIcon icon)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, f.Size, f.Font, backColor, foreColor, false);
f.SetButtons(buttons);
f.SetIcon(icon);
return f.ShowDialog();
}
public static DialogResult show(string text, string title, Color backColor,
Color foreColor, XMessageBoxButtons buttons, Size size, Font font)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, font, backColor, foreColor, true);
f.SetButtons(buttons);
return f.ShowDialog();
}
public static DialogResult show(string text, string title, Color backColor, Color foreColor,
XMessageBoxButtons buttons, XMessageBoxIcon icon, Size size, Font font)
{
XMessageBox f = new XMessageBox();
f.XmessageBox(text, title, size, font, backColor, foreColor, true);
f.SetButtons(buttons);
f.SetIcon(icon);
return f.ShowDialog();
}
回到 Test 项目,右键单击“References”,选择“Add Reference…”,然后切换到“Projects”选项卡,选择“Custom Featured MessageBox”后按“OK”。完成后,在 Form1
中添加命名空间引用。
using Custom_Featured_MessageBox;
添加一个 Button
,双击它,并编写代码
XMessageBox.show("Simple MessageBox with OK button, BackColor is LightSkyBlue " +
"and ForeColor is Black.", "Example",
Color.LightSkyBlue, Color.Black, XMessageBoxButtons.OK);
XMessageBox.show("Simple MessageBox with Abort, Retry and Ignore buttons, BackColor" +
" is LightCyan and ForeColor is Black.", "Example",
Color.LightCyan, Color.Black, XMessageBoxButtons.AbortRetryIgnore);
XMessageBox.show("Error MessageBox with OK button, BackColor is LightGreen " +
"and ForeColor is Black.", "Example", Color.LightGreen,
Color.Black, XMessageBoxButtons.OK, XMessageBoxIcon.Error);
XMessageBox.show("Information MessageBox with Yes and No buttons, BackColor " +
"is LightPink and ForeColor is Black.", "Example",
Color.LightPink, Color.Black, XMessageBoxButtons.YesNo,
XMessageBoxIcon.Information);
现在,是时候检查我们的自定义消息框了。运行解决方案,单击按钮,然后查看结果
现在,我们遇到一个问题,它只显示一行。第二行中的单词“Black”没有显示(由于启用了自动换行,“Black”在第二行)。显然,问题在于高度设置。让我们找出设置高度的位置。然后,我们找到了 XmessageBox
方法,其中有
height = (TextBox1.Lines.Length * TextBox1.Font.Height) + 40 + 40;
…设置高度,在该行上设置一个断点,以便我们知道当前值。
关注点
再次运行,当编译器在断点处停止时,将鼠标悬停在 TextBox1.Lines
的 Length
上(第一个值,它将用于设置高度),我们看到此属性返回“1”。但是,TextBox1
包含两行。这意味着,当启用自动换行时,Length
属性无法正常工作。因此,我们需要显式计算行数。为此,请添加一个类。现在,用此内容替换其所有文本
using System;
using System.Windows.Forms;
namespace Custom_Featured_MessageBox
{
public class XTextBox : TextBox
{
public int LinesCount()
{
Message msg = Message.Create(this.Handle, 0xBA,
IntPtr.Zero, IntPtr.Zero);
base.DefWndProc(ref msg);
return msg.Result.ToInt32();
}
}
}
在上面的代码中,TextBox
被继承,并添加了一个名为 LinesCount
的方法,该方法将返回确切的行长度,即使启用了自动换行。在此方法中,我们向基类的默认窗口过程发送一条消息作为引用。就是这样。
将默认 TextBox
替换为一个新 TextBox
,并将 TextBox1.Lines.Length
替换为 TextBox1.LinesCount()
。现在,替换后的行将看起来像
height = (TextBox1.LinesCount() * TextBox1.Font.Height) + 40 + 40;
现在,运行,是的!它正在工作……!!!
我们还可以添加自己的图像作为图标。为此
- 将图像添加到 Resources 中。
- 在
XMessageBoxIcon
枚举中添加名称(任意名称)。 - 展开
SetIcon
方法。
例如,如果我们想添加一个“Delete”图像作为图标,只需将“Delete”图像添加到 Resources 中,然后展开 XMessageBoxIcon
枚举
public enum XMessageBoxIcon
{ Error, Question, Warning, Information, Delete, }
同样展开“SetIcon
”
void SetIcon(XMessageBoxIcon icon)
{
.
.
.
.
else if (icon == XMessageBoxIcon.Delete)
pictureBox1.BackgroundImage =
Custom_Featured_MessageBox.Properties.Resources.Delete;
}
现在,调用带有该图标的 XmessageBox
XMessageBox.show("Delete MessageBox with Yes, No and " +
"Cancel buttons, BackColor is Control and ForeColor is Black.",
"Example", XMessageBoxButtons.YesNoCancel,
XMessageBoxIcon.Delete);
最后,我们得到了一个消息框,它可以做我们想要的任何事情。请给这篇文章评分,前提是您已经从头到尾读完了它。