自定义消息框

19

我能否创建自己的定制化MessageBox,使其不仅支持字符串,还可以添加图片呢?


你不需要重新发明轮子,兄弟。我曾经有过和你一样的想法,想要自己创建一个解决方案。但是我进行了搜索,并找到了一个适合我的需求的解决方案,我已经在答案中提供了它。 - r.hamd
5个回答

34
我也希望有这个功能,所以我创建了WPFCustomMessageBox,它是原生Windows/.NET MessageBox的WPF克隆版,支持自定义按钮文本等扩展功能。 WPFCustomMessageBox与标准.NET MessageBox一样使用静态方法,因此您可以在不修改任何代码的情况下即插即用新库。最重要的是,我设计了这个控件,使其看起来与原始的MessageBox完全相同

WPFCustomMessageBox example

我创建了这个库是因为我想使用动词来帮助用户更好地理解按钮的功能。使用这个库,您可以提供像 保存 / 不保存 或者 弹出燃料棒 / 不要这样做! 这样的按钮描述,而不是标准的 确认 / 取消 或者 是 / 否(尽管如果您喜欢仍然可以使用它们)。
WPFCustomMessageBox 消息框返回 标准的 .NET MessageBoxResults。它也提供了与原始 MessageBox 相同的功能,如 MessageBoxIcons 和自定义消息框标题。
WPFCustomMessageBox 是开源的,所以您可以在这里获取代码或进行改进:https://github.com/evanwon/WPFCustomMessageBox

您可以通过NuGet将WPFCustomMessage添加到您的项目中:https://www.nuget.org/packages/WPFCustomMessageBox/


+1 给燃料棒...唯一缺少的是:"用过的"..."用过的燃料棒"! :P - MBender
6
基本的用户界面设计原则认为,你可能希望将“不要这样做!”设置为默认按钮,而不是另一个按钮。;-) - James Cronen
1
@Tenner 基本的核燃料棒原理也可能同意这一点 :) - Evan Wondrasek
它能在winform C#中使用吗? - r.hamd

8
以下是创建自己的消息框所需的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyStuff
{
    public class MyLabel : Label
    {
        public static Label Set(string Text = "", Font Font = null, Color ForeColor = new Color(), Color BackColor = new Color())
        {
            Label l = new Label();
            l.Text = Text;
            l.Font = (Font == null) ? new Font("Calibri", 12) : Font;
            l.ForeColor = (ForeColor == new Color()) ? Color.Black : ForeColor;
            l.BackColor = (BackColor == new Color()) ? SystemColors.Control : BackColor;
            l.AutoSize = true;
            return l;
        }
    }
    public class MyButton : Button
    {
        public static Button Set(string Text = "", int Width = 102, int Height = 30, Font Font = null, Color ForeColor = new Color(), Color BackColor = new Color())
        {
            Button b = new Button();
            b.Text = Text;
            b.Width = Width;
            b.Height = Height;
            b.Font = (Font == null) ? new Font("Calibri", 12) : Font;
            b.ForeColor = (ForeColor == new Color()) ? Color.Black : ForeColor;
            b.BackColor = (BackColor == new Color()) ? SystemColors.Control : BackColor;
            b.UseVisualStyleBackColor = (b.BackColor == SystemColors.Control);
            return b;
        }
    }
    public class MyImage : PictureBox
    {
        public static PictureBox Set(string ImagePath = null, int Width = 60, int Height = 60)
        {
            PictureBox i = new PictureBox();
            if (ImagePath != null)
            {
                i.BackgroundImageLayout = ImageLayout.Zoom;
                i.Location = new Point(9, 9);
                i.Margin = new Padding(3, 3, 2, 3);
                i.Size = new Size(Width, Height);
                i.TabStop = false;
                i.Visible = true;
                i.BackgroundImage = Image.FromFile(ImagePath);
            }
            else
            {
                i.Visible = true;
                i.Size = new Size(0, 0);
            }
            return i;
        }
    }
    public partial class MyMessageBox : Form
    {
        private MyMessageBox()
        {
            this.panText = new FlowLayoutPanel();
            this.panButtons = new FlowLayoutPanel();
            this.SuspendLayout();
            // 
            // panText
            // 
            this.panText.Parent = this;
            this.panText.AutoScroll = true;
            this.panText.AutoSize = true;
            this.panText.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            //this.panText.Location = new Point(90, 90);
            this.panText.Margin = new Padding(0);
            this.panText.MaximumSize = new Size(500, 300);
            this.panText.MinimumSize = new Size(108, 50);
            this.panText.Size = new Size(108, 50);
            // 
            // panButtons
            // 
            this.panButtons.AutoSize = true;
            this.panButtons.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            this.panButtons.FlowDirection = FlowDirection.RightToLeft;
            this.panButtons.Location = new Point(89, 89);
            this.panButtons.Margin = new Padding(0);
            this.panButtons.MaximumSize = new Size(580, 150);
            this.panButtons.MinimumSize = new Size(108, 0);
            this.panButtons.Size = new Size(108, 35);
            // 
            // MyMessageBox
            // 
            this.AutoScaleDimensions = new SizeF(8F, 19F);
            this.AutoScaleMode = AutoScaleMode.Font;
            this.ClientSize = new Size(206, 133);
            this.Controls.Add(this.panButtons);
            this.Controls.Add(this.panText);
            this.Font = new Font("Calibri", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            this.Margin = new Padding(4);
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.MinimumSize = new Size(168, 132);
            this.Name = "MyMessageBox";
            this.ShowIcon = false;
            this.ShowInTaskbar = false;
            this.StartPosition = FormStartPosition.CenterScreen;
            this.ResumeLayout(false);
            this.PerformLayout();
        }
        public static string Show(Label Label, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
        {
            List<Label> Labels = new List<Label>();
            Labels.Add(Label);
            return Show(Labels, Title, Buttons, Image);
        }
        public static string Show(string Label, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
        {
            List<Label> Labels = new List<Label>();
            Labels.Add(MyLabel.Set(Label));
            return Show(Labels, Title, Buttons, Image);
        }
        public static string Show(List<Label> Labels = null, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
        {
            if (Labels == null) Labels = new List<Label>();
            if (Labels.Count == 0) Labels.Add(MyLabel.Set(""));
            if (Buttons == null) Buttons = new List<Button>();
            if (Buttons.Count == 0) Buttons.Add(MyButton.Set("OK"));
            List<Button> buttons = new List<Button>(Buttons);
            buttons.Reverse();

            int ImageWidth = 0;
            int ImageHeight = 0;
            int LabelWidth = 0;
            int LabelHeight = 0;
            int ButtonWidth = 0;
            int ButtonHeight = 0;
            int TotalWidth = 0;
            int TotalHeight = 0;

            MyMessageBox mb = new MyMessageBox();

            mb.Text = Title;

            //Image
            if (Image != null)
            {
                mb.Controls.Add(Image);
                Image.MaximumSize = new Size(150, 300);
                ImageWidth = Image.Width + Image.Margin.Horizontal;
                ImageHeight = Image.Height + Image.Margin.Vertical;
            }

            //Labels
            List<int> il = new List<int>();
            mb.panText.Location = new Point(9 + ImageWidth, 9);
            foreach (Label l in Labels)
            {
                mb.panText.Controls.Add(l);
                l.Location = new Point(200, 50);
                l.MaximumSize = new Size(480, 2000);
                il.Add(l.Width);
            }
            Labels.ForEach(l => l.MinimumSize = new Size(Labels.Max(x => x.Width), 1));
            mb.panText.Height = Labels.Sum(l => l.Height);
            mb.panText.MinimumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), ImageHeight);
            mb.panText.MaximumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), 300);
            LabelWidth = mb.panText.Width;
            LabelHeight = mb.panText.Height;

            //Buttons
            foreach (Button b in buttons)
            {
                mb.panButtons.Controls.Add(b);
                b.Location = new Point(3, 3);
                b.TabIndex = Buttons.FindIndex(i => i.Text == b.Text);
                b.Click += new EventHandler(mb.Button_Click);
            }
            ButtonWidth = mb.panButtons.Width;
            ButtonHeight = mb.panButtons.Height;

            //Set Widths
            if (ButtonWidth > ImageWidth + LabelWidth)
            {
                Labels.ForEach(l => l.MinimumSize = new Size(ButtonWidth - ImageWidth - mb.ScrollBarWidth(Labels), 1));
                mb.panText.Height = Labels.Sum(l => l.Height);
                mb.panText.MinimumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), ImageHeight);
                mb.panText.MaximumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), 300);
                LabelWidth = mb.panText.Width;
                LabelHeight = mb.panText.Height;
            }
            TotalWidth = ImageWidth + LabelWidth;

            //Set Height
            TotalHeight = LabelHeight + ButtonHeight;

            mb.panButtons.Location = new Point(TotalWidth - ButtonWidth + 9, mb.panText.Location.Y + mb.panText.Height);

            mb.Size = new Size(TotalWidth + 25, TotalHeight + 47);
            mb.ShowDialog();
            return mb.Result;
        }

        private FlowLayoutPanel panText;
        private FlowLayoutPanel panButtons;
        private int ScrollBarWidth(List<Label> Labels)
        {
            return (Labels.Sum(l => l.Height) > 300) ? 23 : 6;
        }

        private void Button_Click(object sender, EventArgs e)
        {
            Result = ((Button)sender).Text;
            Close();
        }

        private string Result = "";
    }
}   

我花了两天时间写下了这篇文章,希望对需要此信息的任何人都有所帮助。


2
我已经通过标准的WPF控件模板实现了一个可完全自定义的WPF MessageBox: http://blogs.microsoft.co.il/blogs/arik/archive/2011/05/26/a-customizable-wpf-messagebox.aspx 特点:
  • 类WPFMessageBox具有与当前WPF MessageBox类完全相同的接口。
  • 作为自定义控件实现,因此可以通过标准的WPF控件模板进行完全自定义。
  • 具有默认的控件模板,看起来像标准的MessageBox。
  • 支持所有常见类型的消息框:错误、警告、问题和信息。
  • 具有与打开标准MessageBox时相同的“Beep”声音。
  • 支持按Esc键时与标准MessageBox相同的行为。
  • 提供与标准MessageBox相同的系统菜单,包括当消息框处于Yes-No模式时禁用关闭按钮。
  • 处理从右到左的操作系统,与标准MessageBox相同。
  • 提供将所有者窗口设置为WinForms表单控件的支持。

1
当然可以。我通过继承System.Windows.Window并添加显示各种内容(图像、文本和控件)的功能来完成它,然后在该窗口上调用ShowDialog()
public partial class MyMessageBox : Window
{
    // perhaps a helper method here
    public static bool? Show(String message, BitmapImage image)
    {
        // NOTE: Message and Image are fields created in the XAML markup
        MyMessageBox msgBox = new MyMessageBox() { Message.Text = message, Image.Source = image };
        return msgBox.ShowDialog();
    }
}

在XAML中,类似这样的代码:
<Window>
    <DockPanel>
        <Image Name="Image" DockPanel.Dock="Left" />
        <TextBlock Name="Message" />
    </DockPanel>
</Window>

在我的电脑上无法工作,在变量msgBox中,Message和Image会给我报错!! - sikas
@sikas,你一定在使用Visual Studio 2005。上述语法将与VS2008及更高版本中的新C#编译器兼容。如果你被困在VS2005中,请用三行替换“var msgBox…”行:“MyMessageBox msgBox = new MyMessageBox();”,“msgBox.Message = message;”,和“msgBox.Image = image;”。 - Joe White
@silkas - 哎呀,抱歉,我现在太习惯于C# 3.0了... Joe说得完全正确,我已经编辑了答案以反映他的建议。 - codekaizen
在VS2010上,无论如何都无法编译。 - KMC

0

我和你一样有需要,我找到了这个资源并按照自己的方式进行了修改,你也可以从中获得最大的好处

这是链接,默认情况下它看起来像这样:

enter image description here


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