cool hit counter [C#] Share an enhanced message box MessageBoxEx that can carry additional messages_Intefrankly

[C#] Share an enhanced message box MessageBoxEx that can carry additional messages


--------------201806111122 update---------------

updateuntil2 .0。 mainly be Add the ability to customize button text, Another item has been placed onhttps://github .com/ahdung/MessageBoxEx , welcome f**k

--------------201507160917 update---------------

  • I inadvertently found that the standard message box is audible in Windows 7, just silent in Windows server 2008 (R2), and I happen to be using the latter, so I mistakenly thought it was caused by the MessageBeep API not working on all NT6 systems ~ Khan, someone instackoverflow This was also mentioned . But I still decided to use the PlaySound API without modifications
  • Leave the sound processing to the ProcessIcon method . Previously, the MessageBoxIcon and the sound were considered to be loosely coupled, so they were handled separately, but in fact the sound is based on the former, and the two are naturally coupled, so it's superfluous to handle them separately .

--------------201507091034 update---------------

First of all, thank you to the ape friendsE204 Feedback in the responses .

  • Solve the Checked state change problem caused by double-clicking the [Details] button by making ToggleButton ignore WM_LBUTTONDBLCLK messages
  • Fixes to put away the details area logic, Change to direct accessplAttachZone .Height。 prior to be fetchExpandHeight, Can cause visual experience problems

--------------201507082014 original text( then update)---------------

Applies to . . net 2 .0+ ofWinform sports event

Appearance .

It is not possible to show the real effect as it is because of lossy recording + mapping, you can download the demo at the end of the article to experience it .

Functions and features .

  • Centered relative to parent form
  • Additional messages may be attached . The additional message can be of type string and Exception, and the [Details] button will show and hide the additional message depending on whether it is passed in or not . When an Exception instance is passed in, it is presented as an Exception . ToString(), which means it may carry StackTrace information, so if you just want to render the exception text, it's better to pass it honestly into ex . Message
  • Animated effect when expanding/collapsing additional information . If practicality is king, you can also set EnableAnimate=false to turn off animation effects
  • There is also sound feedback on Windows Server 2008 R2 (no other server systems tested) . The standard message box is audible on personal systems (XP/Win7 etc) but not on srv08 . The EnableSound property is also provided to allow you to turn off sound feedback
  • Removed the IWin32Window, MessageBoxOptions and Help related parameters provided by the standard MessageBox, the reason being that I don't use them and am too lazy to implement them
  • You can drag and drop to change the message box size, and the message text and additional text will be rearranged with the form size . This is a capability not provided by the standard message box . Changing the size has different behaviors in two cases: (i) when the details are not expanded, the size of the main message area is changed; (ii) when the details are expanded, the size of the details area is changed

Overall . This message box is more suitable for use where a large amount of message text needs to be fed back If you use a standard message box, too much text may make the message box exceed the screen size, like this guy on codeproject .com citedexamplesThe standard message box does not have the ability to change the size of the form, which will result in some messages not being visible to the user . And even if it doesn't go beyond the screen, it's not an authentic experience to expose users to that much message text at once . Such problems can be solved by using this message box, for example, by displaying summary information in the main message area and placing a large number of detailed messages (e .g ., individual processing situations in batch processing), secondary messages, exception information, etc ., in the details area, where the user or IT support staff can expand to access these messages themselves . Also, you can still use it like a standard message box when there are no additional messages, so if you're like me and won't be using the IWin32Window, MessageBoxOptions and Help related parameters of a standard message box You can basically replace the standard message box with this message box throughout your project Don't forget the additional ability to scale, center relative to the parent form, etc . compared to the standard message box . In a nutshell, you deserve it . As for if you're worried about performance, this ~ I'd say so, I'm still somewhat confident in the quality of my code . too I hope I can get a warrior to point out the slots, appreciate it!

Instructions for use.

First, look at the open membership.

// static property
MessageBoxEx .EnableAnimate
MessageBoxEx .EnableSound

// Static methods
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)
  • The attributes EnableAnimate and EnableSound, mentioned above, are used to enable/disable animation and sound effects, respectively, and by default both are enabled . The scope of the two properties is global, for example, after setting EnableAnimate = false, all subsequent MessageBoxEx popups will have no animation effect until they are reset to true, and the same applies to EnableSound . Best practice is to associate them both with user preference settings, allowing the user to autonomously control
  • There is only one method: Show(), and you probably know how to use it from the list of overloads. The third of these parameters is the additional message, which accepts instances of the string and Exception classes, and the rest of the parameters have the same location and meaning as the standard message box. A brief example is as follows.
MessageBoxEx .Show(" main message", " headline", " Additional News", MessageBoxButtons .OK, MessageBoxIcon .None, MessageBoxDefaultButton .Button1);
MessageBoxEx .Show(" main message", " headline", ex, MessageBoxButtons .OK, MessageBoxIcon .None, MessageBoxDefaultButton .Button1);
  • The first 3 parameters can be safely null, they are handled internally, and you can't null the later enumerations, if you pass in an invalid enum value, an exception will be thrown
  • The method with only 3 string parameters, the last two parameters are optional . So for those of you who are not concerned about the messaging experience you can still use it like this .
MessageBoxEx .Show(" Aston Hair");
MessageBoxEx .Show(" Aston Hair", " scholar officials");

Programme source code.

There is quite a bit of code, for reasons that are natural, and interested children should see the implementation notes later . Also, never assume that the amount of code is directly related to performance; sometimes more code is there precisely to improve performance, and sometimes it's there for robustness .

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>
     /// A message box that can carry detailed information
    /// </summary>
    public static class MessageBoxEx
    {
         //Exception message text
        private const string InvalidButtonExString = " Button parameters are not be Valid enumeration items!";
        private const string InvalidIconExString = " Icon parameters are not be Valid enumeration items!";
        private const string InvalidDfButtonExString = " The default button parameters are not be Valid enumeration items!";

        /// <summary>
         /// Whether to enable animation effects
        /// </summary>
        public static bool EnableAnimate { get; set; }

        /// <summary>
         /// Whether to enable sound feedback
        /// </summary>
        public static bool EnableSound { get; set; }

         //Static construction
        static MessageBoxEx()
        {
             // Enable animation + sound by default
            EnableAnimate = true;
            EnableSound = true;
        }

         #region public method

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="attachMessage"> Additional News</param>
        public static DialogResult Show(string message, string caption = null, string attachMessage = null)
        {
            return ShowCore(message, caption, attachMessage, MessageBoxButtons .OK, MessageBoxIcon .None, MessageBoxDefaultButton .Button1);
        }

         /* The three below are made overloaded rather than optional to avoid unnecessary parameter checking*/

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="attachMessage"> Additional News</param>
        /// <param name="buttons"> Button combinations</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>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="attachMessage"> Additional News</param>
        /// <param name="buttons"> Button combinations</param>
        /// <param name="icon"> icon (computing)</param>
        public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            if (!Enum .IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); }
            if (!Enum .IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); }

            return ShowCore(message, caption, attachMessage, buttons, icon, MessageBoxDefaultButton .Button1);
        }

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="attachMessage"> Additional News</param>
        /// <param name="buttons"> Button combinations</param>
        /// <param name="icon"> icon (computing)</param>
        /// <param name="defaultButton"> Default Button</param>
        public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
        {
            if (!Enum .IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); }
            if (!Enum .IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); }
            if (!Enum .IsDefined(typeof(MessageBoxDefaultButton), defaultButton)) { throw new InvalidEnumArgumentException(InvalidDfButtonExString); }

            return ShowCore(message, caption, attachMessage, buttons, icon, defaultButton);
        }

         /******** pass in exceptions to overload ********/

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="exception"> Example of an exception</param>
        public static DialogResult Show(string message, string caption, Exception exception)
        {
            return Show(message, caption, exception == null ? string .Empty : exception .ToString());
        }

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="exception"> Example of an exception</param>
        /// <param name="buttons"> Button combinations</param>
        public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons)
        {
            return Show(message, caption, exception == null ? string .Empty : exception .ToString(), buttons);
        }

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="exception"> Example of an exception</param>
        /// <param name="buttons"> Button combinations</param>
        /// <param name="icon"> icon (computing)</param>
        public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            return Show(message, caption, exception == null ? string .Empty : exception .ToString(), buttons, icon);
        }

        /// <summary>
         /// Show message box
        /// </summary>
        /// <param name="message"> Message text</param>
        /// <param name="caption"> message box headline</param>
        /// <param name="exception"> Example of an exception</param>
        /// <param name="buttons"> Button combinations</param>
        /// <param name="icon"> icon (computing)</param>
        /// <param name="defaultButton"> Default Button</param>
        public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
        {
            return Show(message, caption, exception == null ? string .Empty : exception .ToString(), buttons, icon, defaultButton);
        }

        #endregion

         // Internal method, no parameter validity check
        private static DialogResult ShowCore(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
        {
            using (MessageForm f = new MessageForm(message, caption, buttons, icon, defaultButton, attachMessage, EnableAnimate, EnableSound))
            {
                return f .ShowDialog();
            }
        }


        /*----------------
          Here are the message form related
         ---------------*/

        /// <summary>
         /// Message form
        /// </summary>
        /// <remarks> The parameter validity is determined by theMessageBoxEx accountable</remarks>
        private class MessageForm : Form
        {
             /* todo Problems.
              * When the message area text is very, very large, and the operation of changing the message box window size, position, expand and collapse is repeated, then at a certain time when expanding
                The details text box may flash momentarily in its original position (i.e., somewhere rect within the message area).
                The reason is that the textbox control will always be displayed at the original position WM_NCPAINT + WM_ERASEBKGND for a while, no solution yet.
                The chances of encountering it in practice are very small, and if you do, the impact is negligible.
             */

#region Control initialization

            /// <summary>
             /// Required designer variables.
            /// </summary>
            private System .ComponentModel .IContainer components = null;

            /// <summary>
             /// Clean up all resources in use.
            /// </summary>
            /// <param name="disposing"> If escrow resources should be released, because of true; deny standard false。</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components .Dispose();
                }
                base .Dispose(disposing);
            }

             #region Windows Forms Designer generated code

            /// <summary>
             /// The designer supports the required methods - don't
             /// Use the code editor to modify the contents of this method.
            /// </summary>
            private void InitializeComponent()
            {
                this .button3 = new System .Windows .Forms .Button();
                this .txbAttach = new TextBoxUnSelectAllable();
                this .button2 = new System .Windows .Forms .Button();
                this .button1 = new System .Windows .Forms .Button();
                this .plButtonsZone = new AhDung .WinForm .MessageBoxEx .MessageForm .PanelBasic();
                this .ckbToggle = new AhDung .WinForm .MessageBoxEx .MessageForm .ToggleButton(this .UseAnimate);
                this .plAttachZone = new AhDung .WinForm .MessageBoxEx .MessageForm .PanelBasic();
                this .lbMsg = new AhDung .WinForm .MessageBoxEx .MessageForm .MessageViewer();
                this .plButtonsZone .SuspendLayout();
                this .plAttachZone .SuspendLayout();
                this .SuspendLayout();
                // 
                // button3
                // 
                this .button3 .Anchor = System .Windows .Forms .AnchorStyles .Top | System .Windows .Forms .AnchorStyles .Right;
                this .button3 .Location = new System .Drawing .Point(320, 8);
                this .button3 .Margin = new System .Windows .Forms .Padding(3, 2, 3, 2);
                this .button3 .Name = "button3";
                this .button3 .Size = new System .Drawing .Size(85, 27);
                this .button3 .TabIndex = 2;
                // 
                // txbAttach
                // 
                this .txbAttach .Anchor = ((System .Windows .Forms .AnchorStyles .Top | System .Windows .Forms .AnchorStyles .Bottom)
                                         | System .Windows .Forms .AnchorStyles .Left)
                                         | System .Windows .Forms .AnchorStyles .Right;
                this .txbAttach .Location = new System .Drawing .Point(10, 7);
                this .txbAttach .Margin = new System .Windows .Forms .Padding(3, 1, 3, 1);
                this .txbAttach .Name = "txbAttach";
                this .txbAttach .ReadOnly = true;
                this .txbAttach .Multiline = true;
                this .txbAttach .ScrollBars = System .Windows .Forms .ScrollBars .Vertical;
                this .txbAttach .Size = new System .Drawing .Size(395, 105);
                this .txbAttach .TabIndex = 0;
                // 
                // button2
                // 
                this .button2 .Anchor = System .Windows .Forms .AnchorStyles .Top | System .Windows .Forms .AnchorStyles .Right;
                this .button2 .Location = new System .Drawing .Point(229, 8);
                this .button2 .Margin = new System .Windows .Forms .Padding(3, 2, 3, 2);
                this .button2 .Name = "button2";
                this .button2 .Size = new System .Drawing .Size(85, 27);
                this .button2 .TabIndex = 1;
                // 
                // button1
                // 
                this .button1 .Anchor = System .Windows .Forms .AnchorStyles .Top | System .Windows .Forms .AnchorStyles .Right;
                this .button1 .Location = new System .Drawing .Point(138, 8);
                this .button1 .Margin = new System .Windows .Forms .Padding(3, 2, 3, 2);
                this .button1 .Name = "button1";
                this .button1 .Size = new System .Drawing .Size(85, 27);
                this .button1 .TabIndex = 0;
                // 
                // plButtonsZone
                // 
                this .plButtonsZone .Controls .Add(this .ckbToggle);
                this .plButtonsZone .Controls .Add(this .button1);
                this .plButtonsZone .Controls .Add(this .button2);
                this .plButtonsZone .Controls .Add(this .button3);
                this .plButtonsZone .Dock = System .Windows .Forms .DockStyle .Bottom;
                this .plButtonsZone .Location = new System .Drawing .Point(0, 96);
                this .plButtonsZone .Margin = new System .Windows .Forms .Padding(3, 1, 3, 1);
                this .plButtonsZone .Name = "plButtonsZone";
                this .plButtonsZone .Size = new System .Drawing .Size(415, 36);
                this .plButtonsZone .TabIndex = 1;
                // 
                // ckbToggle
                // 
                this .ckbToggle .Location = new System .Drawing .Point(10, 8);
                this .ckbToggle .Name = "ckbToggle";
                this .ckbToggle .Size = new System .Drawing .Size(93, 27);
                this .ckbToggle .TabIndex = 3;
                this .ckbToggle .Text = " Detailed information(&D)";
                this .ckbToggle .CheckedChanged += this .ckbToggle_CheckedChanged;
                // 
                // plAttachZone
                // 
                this .plAttachZone .Controls .Add(this .txbAttach);
                this .plAttachZone .Dock = System .Windows .Forms .DockStyle .Fill;
                this .plAttachZone .Location = new System .Drawing .Point(0, 130);
                this .plAttachZone .Margin = new System .Windows .Forms .Padding(3, 2, 3, 2);
                this .plAttachZone .Name = "plAttachZone";
                this .plAttachZone .Size = new System .Drawing .Size(415, 114);
                this .plAttachZone .TabIndex = 2;
                this .plAttachZone .Visible = false;
                // 
                // lbMsg
                // 
                this .lbMsg .Dock = System .Windows .Forms .DockStyle .Fill;
                this .lbMsg .Icon = null;
                this .lbMsg .Location = new System .Drawing .Point(0, 0);
                this .lbMsg .Name = "lbMsg";
                this .lbMsg .Padding = new System .Windows .Forms .Padding(21, 18, 21, 18);
                //this .lbMsg .Size = new System .Drawing .Size(415, 96);
                this .lbMsg .TabIndex = 0;
                // 
                // FmMsg
                // 
                this .AutoScaleMode = System .Windows .Forms .AutoScaleMode .None;
                //this .ClientSize = new System .Drawing .Size(415, 261);
                this .Controls .Add(this .lbMsg);
                this .Controls .Add(this .plButtonsZone);
                this .Controls .Add(this .plAttachZone);
                this .DoubleBuffered = true;
                this .MaximizeBox = false;
                this .Name = "MessageForm";
                this .Padding = new System .Windows .Forms .Padding(0, 0, 0, 17);
                this .ShowIcon = false;
                this .ShowInTaskbar = false;
                this .SizeGripStyle = System .Windows .Forms .SizeGripStyle .Show;
                this .plButtonsZone .ResumeLayout(false);
                this .plAttachZone .ResumeLayout(false);
                this .plAttachZone .PerformLayout();
                this .ResumeLayout(false);
            }

            #endregion

            private ToggleButton ckbToggle;
            private TextBoxUnSelectAllable txbAttach;
            private MessageViewer lbMsg;
            private System .Windows .Forms .Button button2;
            private System .Windows .Forms .Button button1;
            private PanelBasic plButtonsZone;
            private PanelBasic plAttachZone;
            private System .Windows .Forms .Button button3;

            #endregion

            /// <summary>
             /// Maximum default form client area width
            /// </summary>
            const int MaxClientWidth = 700;

             string messageSound;// Store the system message sound alias for use by the PlaySound API, assigned in ProcessIcon and taken in OnShown

            int expandHeight;
            /// <summary>
             /// Details area expand height
            /// </summary>
            private int ExpandHeight
            {
                get { return expandHeight < 150 ? 150 : expandHeight; }
                set { expandHeight = value; }
            }

             #region property

            /// <summary>
             /// Whether to enable animation effects
            /// </summary>
            /// <remarks> This also gets the property be To ensure the independence of the form class</remarks>
            private bool UseAnimate { get; set; }

            /// <summary>
             /// Whether to enable sound feedback
            /// </summary>
            /// <remarks> This also gets the property be To ensure the independence of the form class</remarks>
            private bool UseSound { get; set; }

            /// <summary>
             /// Message button
            /// </summary>
            private MessageBoxButtons MessageButtons { get; set; }

            /// <summary>
             /// Message icon
            /// </summary>
            private MessageBoxIcon MessageIcon { get; set; }

            /// <summary>
             /// Default button
            /// </summary>
            private MessageBoxDefaultButton DefaultButton { get; set; }

            #endregion

            /// <summary>
             /// Create a message form
            /// </summary>
            private MessageForm(bool enableAnimate)
            {
                this .UseAnimate = enableAnimate;// Must be set up early, To initialize the expand button
                InitializeComponent();
                this .StartPosition = Form .ActiveForm == null ? FormStartPosition .CenterScreen : FormStartPosition .CenterParent;
                this .Font = SystemFonts .MessageBoxFont;

                 // Registering events
                this .button1 .Click += button_Click;
                this .button2 .Click += button_Click;
                this .button3 .Click += button_Click;
                this .plAttachZone .Resize += plAttachZone_Resize;
            }

            /// <summary>
             /// Create a message form
            /// </summary>
            public MessageForm(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, string attachMessage, bool enableAnimate, bool enableSound)
                : this(enableAnimate)
            {
                this .lbMsg .Text = message;
                this .Text = caption;
                this .txbAttach .Text = attachMessage;
                this .MessageButtons = buttons;
                this .MessageIcon = icon;
                this .DefaultButton = defaultButton;
                this .UseSound = enableSound;
            }

#region Override base class methods

            protected override void OnLoad(EventArgs e)
            {
                 // must be done before calculating various dimensions
                ProcessIcon();
                ProcessButtons();

                this .MinimumSize = SizeFromClientSize(new Size(GetPanelButtonMinWidth(), GetClientMinHeight()));

                 // The meaning of the parameter is set to the maximum size of the client area, so it needs to be passed in after shaving off the height of the non-client area
                this .ClientSize = this .GetPreferredSize(new Size(MaxClientWidth, Screen .PrimaryScreen .WorkingArea .Height - (this .Height - this .ClientSize .Height)));

                base .OnLoad(e);
            }

            protected override void OnShown(EventArgs e)
            {
                 // Set the default button focus. Button focus must be set in OnShown to be useful
                Button dfBtn;
                if ((dfBtn = this .AcceptButton as Button) != null)
                {
                    dfBtn .Focus();
                }

                 /play message alert tone
                if (this .UseSound) { PlaySystemSound(this .messageSound); }

                base .OnShown(e);
            }

             // Rewrite form parameters
            protected override CreateParams CreateParams
            {
                get
                {
                    CreateParams prms = base .CreateParams;

                    if ((Convert .ToInt32(this .MessageButtons) & 1) == 0) // not haveCancel Block off button when button, Just in the even numbered term
                    {
                        prms .ClassStyle |= 0x200;
                    }

                    return prms;
                }
            }

            /// <summary>
             /// Calculate the appropriate window size
            /// </summary>
            /// <param name="proposedSize"> This parameter is defined here as the maximum size that can be set for the client area</param>
            public override Size GetPreferredSize(Size proposedSize)
            {
                int reservedHeight = plButtonsZone .Height + Padding .Bottom;
                Size size = lbMsg .GetPreferredSize(new Size(proposedSize .Width, proposedSize .Height - reservedHeight));
                size .Height += reservedHeight;
                return size;
            }

            #endregion

             #region Event handling methods

             // Expand to close
            private void ckbToggle_CheckedChanged(object sender, EventArgs e)
            {
                this .SuspendLayout();

                if (ckbToggle .Checked)
                {
                    plButtonsZone .SendToBack();
                    lbMsg .SendToBack();

                    lbMsg .Dock = DockStyle .Top;
                    plButtonsZone .Dock = DockStyle .Top;

                    ChangeFormHeight(ExpandHeight);
                    plAttachZone .Visible = true;
                }
                else
                {
                    ExpandHeight = plAttachZone .Height;// To unfold the height of memory again
                    plAttachZone .Visible = false;
                    ChangeFormHeight(-plAttachZone .Height);// Pick up directly when you put it awaypl high level, Don't takeExpandHeight

                    plButtonsZone .SendToBack();

                    plButtonsZone .Dock = DockStyle .Bottom;
                    lbMsg .Dock = DockStyle .Fill;
                }

                this .ResumeLayout();
            }

             // Button events
            private void button_Click(object sender, EventArgs e)
            {
                this .DialogResult = (DialogResult)((sender as Button) .Tag);
            }

             // Collapse is triggered when the user manually closes the detail area
            private void plAttachZone_Resize(object sender, EventArgs e)
            {
                if (ckbToggle .Checked && plAttachZone .Height == 0)
                {
                    ckbToggle .Checked = false;
                }
            }

            #endregion

             #region helper + private methods

            /// <summary>
             /// Handles button-related
            /// </summary>
            private void ProcessButtons()
            {
                this .ckbToggle .Visible = txbAttach .Text .Trim() .Length != 0; // No details, no expand button

                 int btnCount = 3;  // Number of buttons

switch (MessageButtons) // honestly use case, readable point
                {
                    case MessageBoxButtons .AbortRetryIgnore:
                        button1 .Text = " suspend(&A)"; button1 .Tag = DialogResult .Abort;
                        button2 .Text = " retry(&R)"; button2 .Tag = DialogResult .Retry;
                        button3 .Text = " neglect(&I)"; button3 .Tag = DialogResult .Ignore;
                        break;
                    case MessageBoxButtons .OK:
                        button1 .Visible = false;
                        button2 .Visible = false;
                        button3 .Text = " identify"; button3 .Tag = DialogResult .OK;
                        btnCount = 1;
                        break;
                    case MessageBoxButtons .OKCancel:
                        button1 .Visible = false;
                        button2 .Text = " identify"; button2 .Tag = DialogResult .OK;
                        button3 .Text = " cancellation"; button3 .Tag = DialogResult .Cancel;
                        btnCount = 2;
                        break;
                    case MessageBoxButtons .RetryCancel:
                        button1 .Visible = false;
                        button2 .Text = " retry(&R)"; button2 .Tag = DialogResult .Retry;
                        button3 .Text = " cancellation"; button3 .Tag = DialogResult .Cancel;
                        btnCount = 2;
                        break;
                    case MessageBoxButtons .YesNo:
                        button1 .Visible = false;
                        button2 .Text = " be(&Y)"; button2 .Tag = DialogResult .Yes;
                        button3 .Text = " deny(&N)"; button3 .Tag = DialogResult .No;
                        btnCount = 2;
                        break;
                    case MessageBoxButtons .YesNoCancel:
                        button1 .Text = " be(&Y)"; button1 .Tag = DialogResult .Yes;
                        button2 .Text = " deny(&N)"; button2 .Tag = DialogResult .No;
                        button3 .Text = " cancellation"; button3 .Tag = DialogResult .Cancel;
                        break;
                    default: break;
                }

                 //CancelButton only when OK and Cancel buttons are available
                if ((int)MessageButtons == 0 || ((int)MessageButtons & 1) == 1)
                {
                    this .CancelButton = button3;
                }

                 // Handling the default button
                if (btnCount == 1)
                {
                    this .AcceptButton = button3;
                }
                else if (btnCount == 2)
                {
                    this .AcceptButton = DefaultButton == MessageBoxDefaultButton .Button2 ? button3 : button2;
                }
                else
                {
                    Button[] btnArray = { button1, button2, button3 };
                    this .AcceptButton = btnArray[Convert .ToInt32(DefaultButton) / 0x100];
                }
            }

            /// <summary>
             /// Processing icons (with sound)
            /// </summary>
            private void ProcessIcon()
            {
                switch (MessageIcon)
                {
                    //MessageBoxIcon .Information equivalent
                    case MessageBoxIcon .Asterisk:
                        lbMsg .Icon = SystemIcons .Information;
                        messageSound = "SystemAsterisk";
                        break;

                    //MessageBoxIcon .Hand、MessageBoxIcon .Stop equivalent
                    case MessageBoxIcon .Error:
                        lbMsg .Icon = SystemIcons .Error;
                        messageSound = "SystemHand";
                        break;

                    //MessageBoxIcon .Warning equivalent
                    case MessageBoxIcon .Exclamation:
                        lbMsg .Icon = SystemIcons .Warning;
                        messageSound = "SystemExclamation";
                        break;

                    case MessageBoxIcon .Question:
                        lbMsg .Icon = SystemIcons .Question;
                        messageSound = "SystemAsterisk";//Question original be dumb, This realization lets it rub off a littleInformation of
                        break;

                    default: //MessageBoxIcon .None
                        lbMsg .Icon = null;
                        messageSound = "SystemDefault";
                        break;
                }
            }

            /// <summary>
             /// Calculates the minimum height of the client area of the form
            /// </summary>
            private int GetClientMinHeight()
            {
                return lbMsg .MinimumHeight + plButtonsZone .Height + Padding .Bottom;
            }

            /// <summary>
             /// Calculates the minimum width of the button area
            /// </summary>
            private int GetPanelButtonMinWidth()
            {
                 int r = 20 /*Left and Right Padding*/, visibleCount = -1 /*Because more than two are spaced out*/;

                if (ckbToggle .Visible) { r += ckbToggle .Width; visibleCount++; }
                if (button1 .Visible) { r += button1 .Width * 3; visibleCount += 3; }
                else if (button2 .Visible) { r += button2 .Width * 2; visibleCount += 2; }
                else { r += button3 .Width; visibleCount++; }

                 if (visibleCount != -1) { r += visibleCount * 6;  } // Button spacing

                return r;
            }

            /// <summary>
             /// Change the height of the form. Animated in-house
            /// </summary>
            /// <param name="increment"> incremental( A negative number is a reduction in height)</param>
            private void ChangeFormHeight(int increment)
            {
                int finalHeight = this .Height + increment; // The right target height

                if (!this .UseAnimate) // No animation
                {
                    this .Height = finalHeight;
                    return;
                }

                 const int step = 8;  //Frames

                for (int i = 0; i < step; i++)
                {
                     if (i == step - 1) // the last step goes straight to the goal
                    {
                        this .Height = finalHeight;
                        return;
                    }

                    this .Height += increment / step;

                    Application .DoEvents(); // necessary
                    Thread .Sleep(10);
                }
            }

            /// <summary>
             /// Play system event sound
            /// </summary>
            /// <remarks> The reason for not usingMessageBeep API be Because this one is insrv08 keep silent, So usePlaySound substitute for</remarks>
            private static void PlaySystemSound(string soundAlias)
            {
                PlaySound(soundAlias, IntPtr .Zero, 0x10000 /*SND_ALIAS*/| 0x1 /*SND_ASYNC*/);
            }

            [DllImport("winmm .dll", CharSet = CharSet .Auto)]
            private static extern bool PlaySound([MarshalAs(UnmanagedType .LPWStr)] string soundName, IntPtr hmod, int soundFlags);

            #endregion

             #region nested classes

            /// <summary>
             /// Basic panel
            /// </summary>
            private class PanelBasic : Control
            {
                public PanelBasic()
                {
                    SetStyle(ControlStyles .AllPaintingInWmPaint, false);// crux, Otherwise its onToolBar abnormal
                    SetStyle(ControlStyles .OptimizedDoubleBuffer, true);// important。 If not set, the control does not draw properly
                    SetStyle(ControlStyles .ContainerControl, true);
                    SetStyle(ControlStyles .Selectable, false);
                }

                protected override void WndProc(ref Message m)
                {
                     // Mask WM_ERASEBKGND. Prevents flashing in the original position when displayed
                    // Cannot passControlStyles .AllPaintingInWmPaint=true shield
                     // will affect the ToolBar on it
                    if (m .Msg == 0x14) { return; }

                    base .WndProc(ref m);
                }

                protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
                {
                     Panel stays in place briefly during //Anti-Dock
                    base .SetBoundsCore(x, y, width, height, specified | BoundsSpecified .Y | BoundsSpecified .Width);
                }
            }

            /// <summary>
             /// Message presentation control
            /// </summary>
            private class MessageViewer : Control
            {
                const TextFormatFlags textFlags = TextFormatFlags .EndEllipsis // unfinished ellipsis
                                                  | TextFormatFlags .WordBreak // Line feeds allowed
                                                  | TextFormatFlags .NoPadding // margin-free
                                                  | TextFormatFlags .ExternalLeading // Gaps between lines。NT5 necessary, Otherwise the words are crammed together
                                                  | TextFormatFlags .TextBoxControl; // Avoid half rows

                 const int IconSpace = 5;  // Icon and text spacing

                 const float PreferredScale = 13;// optimal text block scale (width/height)

                /// <summary>
                 /// Minimum height. Don't override MinimumSize, that will be executed both when the form is moved and scaled
                /// </summary>
                public int MinimumHeight
                {
                    get
                    {
                        return (this .Icon != null ? Math .Max(this .Icon .Height, this .FontHeight) : this .FontHeight) + Padding .Vertical;
                    }
                }

                /// <summary>
                 /// Get or set icons
                /// </summary>
                public Icon Icon { get; set; }

                public MessageViewer()
                {
                    this .SetStyle(ControlStyles .CacheText, true);
                    this .SetStyle(ControlStyles .UserPaint, true);
                    this .SetStyle(ControlStyles .AllPaintingInWmPaint, true);
                    this .SetStyle(ControlStyles .Selectable, false);
                    this .SetStyle(ControlStyles .ResizeRedraw, true); // important

                    this .DoubleBuffered = true; // double buffer
                    BackColor = Environment .OSVersion .Version .Major == 5 ? SystemColors .Control : Color .White;
                }

                 //Anti-Dock change size
                protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
                {
                    base .SetBoundsCore(x, y, width, height, specified | BoundsSpecified .Size);
                }

                /// <summary>
                 /// Calculate the appropriate message area size
                /// </summary>
                /// <param name="proposedSize"> This parameter is defined here as the maximum size that can be set for this control</param>
                /// <remarks> This method is scaled to optimize for single lines of text that are too long, Prevents users from twisting their necks by swinging their heads too far</remarks>
                public override Size GetPreferredSize(Size proposedSize)
                {
                    if (proposedSize .Width < 10) { proposedSize .Width = int .MaxValue; }
                    if (proposedSize .Height < 10) { proposedSize .Height = int .MaxValue; }

                    int reservedWidth = Padding .Horizontal + (this .Icon == null ? 0 : (this .Icon .Width + IconSpace));

                    Size wellSize = Size .Empty;
                    if (!string .IsNullOrEmpty(this .Text))
                    {
                         // Optimize text block aspect ratio
                        Size size = TextRenderer .MeasureText(this .Text, this .Font, new Size(proposedSize .Width - reservedWidth, 0), textFlags);// Measure the text area with the specified width
                        wellSize = Convert .ToSingle(size .Width) / size .Height > PreferredScale // Excessively wide and flat
                            ? Size .Ceiling(GetSameSizeWithNewScale(size, PreferredScale))
                            : size;

                         // round up to full line height to ensure trailing lines are displayed
                        int lineHeight = TextRenderer .MeasureText(" ", this .Font, new Size(int .MaxValue, 0), textFlags) .Height;// single row high,Font .Height unreliable
                        int differ;
                        wellSize .Height += (differ = wellSize .Height % lineHeight) == 0 ? 0 : (lineHeight - differ);
                    }
                    if (this .Icon != null)
                    {
                        wellSize .Width += this .Icon .Width + IconSpace;
                        wellSize .Height = Math .Max(this .Icon .Height, wellSize .Height);
                    }
                    wellSize += Padding .Size;

                     // Should not exceed the specified size. The width has been ensured above that it will not exceed
                    if (wellSize .Height > proposedSize .Height) { wellSize .Height = proposedSize .Height; }

                    return wellSize;
                }

                /// <summary>
                 /// Redrawn
                /// </summary>
                protected override void OnPaint(PaintEventArgs e)
                {
                    Graphics g = e .Graphics;
                    Rectangle rect = GetPaddedRectangle();

                     // Drawing icons
                    if (this .Icon != null)
                    {
                        g .DrawIcon(this .Icon, Padding .Left, Padding .Top);

                         // Move text area right
                        rect .X += this .Icon .Width + IconSpace;
                        rect .Width -= this .Icon .Width + IconSpace;

                         // If too little text, center vertically with the icon
                        if (this .Text .Length < 100)
                        {
                            Size textSize = TextRenderer .MeasureText(g, this .Text, this .Font, rect .Size, textFlags);
                            if (textSize .Height <= this .Icon .Height)
                            {
                                rect .Y += (this .Icon .Height - textSize .Height) / 2;
                            }
                        }
                    }

                    //g .FillRectangle(Brushes .Gainsboro, rect);//test

                     // Draw text
                    TextRenderer .DrawText(g, this .Text, this .Font, rect, Color .Black, textFlags);

                    base .OnPaint(e);
                }

                /// <summary>
                 /// Based on the original size, a new size with the same area and the specified scale is obtained
                /// </summary>
                /// <param name="src"> original size</param>
                /// <param name="scale"> New size ratio。 require bewidth/height</param>
                private static SizeF GetSameSizeWithNewScale(Size src, float scale)
                {
                    int sqr = src .Width * src .Height;// original area
                    double w = Math .Sqrt(sqr * scale);// New area width
                    return new SizeF(Convert .ToSingle(w), Convert .ToSingle(sqr / w));
                }

                /// <summary>
                 /// Get the content area minus the Padding
                /// </summary>
                private Rectangle GetPaddedRectangle()
                {
                    Rectangle r = this .ClientRectangle;
                    r .X += this .Padding .Left;
                    r .Y += this .Padding .Top;
                    r .Width -= this .Padding .Horizontal;
                    r .Height -= this .Padding .Vertical;
                    return r;
                }
            }

            /// <summary>
             /// Text box for blocking full select messages
            /// </summary>
            private class TextBoxUnSelectAllable : TextBox
            {
                protected override void WndProc(ref Message m)
                {
                    //EM_SETSEL
                    if (m .Msg == 0xB1) { return; }

                    base .WndProc(ref m);
                }
            }

            /// <summary>
             /// Wrapping ToolBarButton as a single control
            /// </summary>
            private class ToggleButton : Control
            {
                /// <summary>
                 /// Expand/ Collapse icon data
                /// </summary>
                const string ImgDataBase64 =
@"iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAA3NJREFUeNqklVlPFEEQx/8zPccue6gorMd6gBegeCAQD4w+oCx+AInx
IB4EfTK8+g2MQUUTcBU8En0wmvigEkyMxgcTjRrUqHFVUBRQQaJGl2WPmbG6dzCLWUiESf7T0739
666urqqVDjVcxT9PAWkfqZKUY491ktpIzaRXGPv5L15J+dZIRx26dqAwf56c48+Cx+1CzDDR//13
/seevvx3HZ8OxmLxMzSvjhT5Z+Nx8UoKfHOu31e+qWwZPBkOMBkwTAvRuAE21QuvJwNz5s6U25++
rv365dtC+4SxifJsfeVWvsCJ2TOzqyo2FsHt1OBSFeiqTItIsOhHw7JgGBZM+s72TcOvX+GccHgw
k7qttgHj5slOLNE0tXZNSQGYJEEhiDEJusLoW4ZMfZnGJVv0QmHhYuiaup+zE+W5Aftyc/xMURRh
acJIKpowqDVhkhu5LCspiY6k0OIL5s9mdrCNyp9sDKL+6PExeW5AwOebigRNiiVMkoFIPIFwlLcG
huIm4mRI3DRpAQg38oPMmD6Nuz4wGn+koRGH64/hxr1HuHjl2qg8D8JcZ4ZTRCtLSDjT1Ijz51rS
5lfVzj2o2rWXXCzDPcnNh3L5K5WntdHYdAqng6cwa/EK+AuK8SDUSx65gUAlxR1ZkcqLLDBpkJ+S
R8yOvbXw+vx4GOoZsXlZyQqsK10pNlDpjlVZDPMs0FL55mATLl04C39+EWblFf3l2zs+w7jZii1b
Kkfw3IDOcDiS5/G4yLjknQcCAbrPW3j8plvMWlu8XGwOsblMASYjFh3i3S4SS+W3Vddg++6apJ8t
OwN4HHH/p+G5AW3f+gbyvB632DwGHigSyjdvpn4b9ElZWF9aJE6uMAanJsOlK3jdNcAXuE2y0vEQ
rcXfyeCT0vPcES0funoNRTJpgixSRUQsLbapogIbVq8S47rKCORShQvbX7437NI6Km8Ol9sxeG7A
i2g0Fnz2PAQ3TcjQGBw02UGWOqig8L7bweB1qCSFxHD3/nMMDkWDnJ0oP1yK6z529y1i8ovydaVL
wXOaXxl3W7K4yKKykY/Rdq8dofe9d+x6jonyw6WYu+Pyj5/hzLedPcU61dDJLh1T3E4BRgYjCHV0
4/qdJ+bn/h+naW41KZpiwLh5Kc3fMS+vNXaRybVT7YMdcM2228d6/ov/I8AAPfkI7yO+mM8AAAAA
SUVORK5CYII=";

                readonly bool isToggleMode;
                bool isChecked;
                bool useAnimate;
                readonly ImageList imgList;

                /// <summary>
/// After Checked changes
                /// </summary>
                public event EventHandler CheckedChanged;

                /// <summary>
                 /// Using animated button effects
                /// </summary>
                private bool UseAnimate
                {
                    get { return useAnimate; }
                    set
                    {
                        if (useAnimate == value) { return; }

                        useAnimate = value;
                        if (IsHandleCreated) { this .CreateHandle(); }
                    }
                }

                /// <summary>
                ///  Get or set button be deny In the pressed state
                /// </summary>
                [Description(" Get or set button be deny In the pressed state"), DefaultValue(false)]
                public bool Checked
                {
                    get
                    {
                        if (IsHandleCreated)
                        {
                             // Ensure that isChecked matches the reality. TB_ISBUTTONCHECKED
                            isChecked = Convert .ToBoolean(SendMessage(this .Handle, 0x40A, IntPtr .Zero, IntPtr .Zero) .ToInt32());
                        }
                        return isChecked;
                    }
                    set
                    {
                        if (isChecked == value || !isToggleMode) { return; }

                        isChecked = value;

                        if (IsHandleCreated)
                        {
                            //TB_CHECKBUTTON
                            SendMessage(this .Handle, 0x402, IntPtr .Zero, new IntPtr(Convert .ToInt32(value)));
                        }

                        OnCheckedChanged(EventArgs .Empty);
                    }
                }

                /// <summary>
                 /// Create ToolBarButtonControl
                /// </summary>
                public ToggleButton(bool useAnimate)
                {
                    SetStyle(ControlStyles .UserPaint, false);
                    SetStyle(ControlStyles .AllPaintingInWmPaint, true);
                    SetStyle(ControlStyles .OptimizedDoubleBuffer, true);
                    SetStyle(ControlStyles .ResizeRedraw, true);

                    this .isToggleMode = true;// Just write it down., Settings are only available in the standalone version
                    this .UseAnimate = useAnimate;

                     // Add the icon to the imageList
                    imgList = new ImageList { ImageSize = new System .Drawing .Size(16, 16), ColorDepth = ColorDepth .Depth32Bit };
                    using (MemoryStream ms = new MemoryStream(Convert .FromBase64String(ImgDataBase64)))
                    {
                        imgList .Images .AddStrip(Image .FromStream(ms));
                    }
                }

                /// <summary>
                 /// Perform a left-click
                /// </summary>
                public void PerformClick()
                {
                    SendMessage(this .Handle, 0x201, new IntPtr(0x1), IntPtr .Zero);//WM_LBUTTONDOWN
                    Application .DoEvents();
                    SendMessage(this .Handle, 0x202, IntPtr .Zero, IntPtr .Zero);    //WM_LBUTTONUP
                }

                protected override void WndProc(ref Message m)
                {
                    // neglect Mouse double click on message,WM_LBUTTONDBLCLK
                    if (m .Msg == 0x203) { return; }

                     // Modestly responsive mouse movements
                    if ((m .Msg == 0x201 || m .Msg == 0x202) && (!this .Enabled || !this .Visible))
                    {
                        return;
                    }
                    base .WndProc(ref m);
                }

                 // Create ToolBar
                protected override CreateParams CreateParams
                {
                    get
                    {
                        CreateParams prms = base .CreateParams;
                        prms .ClassName = "ToolbarWindow32";
                        prms .Style = 0x40000000
                            | 0x10000000
                            //| 0x2000000 //WS_CLIPCHILDREN
                            //| 0x8000
                            | 0x1
                            | 0x4
                            | 0x8
                            | 0x40
                             |  0x1000 //TBSTYLE_LIST, icon text horizontal row
                            ;
                        if (UseAnimate) { prms .Style |= 0x800; }//TBSTYLE_FLAT。flat The model is inNT6 .x downwards, Button presses will animate

                        prms .ExStyle = 0;

                        return prms;
                    }
                }

                protected override void OnHandleCreated(EventArgs e)
                {
                    base .OnHandleCreated(e);

                     // Set imgList
                    SendMessage(this .Handle, 0x430, IntPtr .Zero, imgList .Handle);//TB_SETIMAGELIST

                     // Prepare to add button
                    int btnStructSize = Marshal .SizeOf(typeof(TBBUTTON));
                    SendMessage(this .Handle, 0x41E, new IntPtr(btnStructSize), IntPtr .Zero);//TB_BUTTONSTRUCTSIZE, Must be added before the button

                     // Build button information
                    TBBUTTON btnStruct = new TBBUTTON
                    {
                        //iBitmap = 0,
                        //idCommand = 0,
                        fsState = 0x4, //TBSTATE_ENABLED
                        iString = SendMessage(this .Handle, 0x44D, 0, this .Text + '')//TB_ADDSTRING
                    };
                    if (this .isToggleMode) { btnStruct .fsStyle = 0x2; }//BTNS_CHECK。 When used as a toggle button

                    IntPtr btnStructStart = IntPtr .Zero;
                    try
                    {
                        btnStructStart = Marshal .AllocHGlobal(btnStructSize);// Create a pointer in the unmanaged area
                        Marshal .StructureToPtr(btnStruct, btnStructStart, true);// Stuff the structure with the above pointer

                         // Add button
                        SendMessage(this .Handle, 0x444, new IntPtr(1)/* Number of buttons*/, btnStructStart);//TB_ADDBUTTONS。 Fetch button information from pointer

                         // Set the button size just to the ToolBar size
                        AdjustButtonSize();
                    }
                    finally
                    {
                        if (btnStructStart != IntPtr .Zero) { Marshal .FreeHGlobal(btnStructStart); }
                    }
                }

                protected override bool ProcessCmdKey(ref Message m, Keys keyData)
                {
                     // treat spaces and carriage returns as mouse clicks
                    if (m .Msg == 0x100 && (keyData == Keys .Enter || keyData == Keys .Space))
                    {
                        PerformClick();
                        return true;
                    }

                    return base .ProcessCmdKey(ref m, keyData);
                }

                /// <summary>
                 /// Processing of helper keys
                /// </summary>
                protected override bool ProcessMnemonic(char charCode)
                {
                    if (IsMnemonic(charCode, this .Text))
                    {
                        PerformClick();
                        return true;
                    }

                    return base .ProcessMnemonic(charCode);
                }

                protected override void OnClick(EventArgs e)
                {
                    // neglect right mouse button
                    MouseEventArgs me = e as MouseEventArgs;
                    if (me != null && me .Button != System .Windows .Forms .MouseButtons .Left)
                    { return; }

                    // if be switch modes, direct triggerChecked events( Don't set theChecked Property triggered, owing toOnClick It was sent beforeCheck finish)
                     // There is theoretical unreliability, but no better way for now
                    if (isToggleMode)
                    { this .OnCheckedChanged(EventArgs .Empty); }

                    base .OnClick(e);
                }

                 //Redraw after resizing buttons
                protected override void OnInvalidated(InvalidateEventArgs e)
                {
                    base .OnInvalidated(e);
                    AdjustButtonSize();
                }

                /// <summary>
                 /// Raises the CheckedChanged event
                /// </summary>
                protected virtual void OnCheckedChanged(EventArgs e)
                {
                    SetImageIndex(this .Checked ? 1 : 0);

                    if (CheckedChanged != null) { CheckedChanged(this, e); }
                }

                /// <summary>
                 /// Set the icon index
                /// </summary>
                private void SetImageIndex(int index)
                {
                    //TB_CHANGEBITMAP
                    SendMessage(this .Handle, 0x42B, IntPtr .Zero, new IntPtr(index));
                }

                /// <summary>
/// Resize the button just to the ToolBar size
                /// </summary>
                private void AdjustButtonSize()
                {
                    IntPtr lParam = new IntPtr((this .Width & 0xFFFF) | (this .Height << 0x10)); //MakeLParam technique
                    SendMessage(this .Handle, 0x41F, IntPtr .Zero, lParam); //TB_SETBUTTONSIZE
                }

                #region Win32 API

                [DllImport("user32 .dll", CharSet = CharSet .Auto)]
                private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

                [DllImport("user32 .dll", CharSet = CharSet .Auto)]
                private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, string lParam);

                [StructLayout(LayoutKind .Sequential)]
                private struct TBBUTTON
                {
                    public int iBitmap;
                    public int idCommand;
                    public byte fsState;
                    public byte fsStyle;
                    public byte bReserved0;
                    public byte bReserved1;
                    public IntPtr dwData;
                    public IntPtr iString;
                }

                #endregion
            }

            #endregion
        }
    }
}

Description of implementation .

The following is dedicated to those who love to "gossip" and have egg on their face. Here's an outline class diagram to start with, the full demo is available for download later in detail, so you can down back and take your time with it.

  • certainShow in all be Calling the privateShowCore approach, this one be Imitation criteriaMessageBox naming of。 As for the significance, be Because the public method has to do parameter checking, The code that passes the check can then be reused。 additionally, Several methods of existence parameter checking are be Calling internal methods, rather than be Adjust the load with the most complete parameters, also be Because try to avoid unnecessary parameter checks, Because the public method with the most complete parameters, Parameters check nature be do the most, So the less-involved method would have ensured the incoming be Legal arguments, but because of the tune it, will result in unnecessary checks, The internal approach can be avoided, Because internal methods should be designed not to do or do less parameter checking。 That's it be I would like to remind beginners of the handling of these details, Performance should be picked up from the fine spot
  • The static class MessageBoxEx maintains a MessageForm form class (hereafter referred to as MsgFm) inside, which instantiates a MsgFm each time a Show is made and is released when the Show is finished . Almost all of the capabilities are provided by the latter, with the former simply wrapping and exposing them, so the following is mostly about MsgFm . Also, depending on whether the MessageBoxButtons passed in have a Cancel item or not, it will enable/block the close button in the top right corner of the form, because the result of clicking the close button on the dialog is always DialogResult .Cancel, so if it is not blocked, when passing in parameters like YesNo, the caller may get a result other than Yes, No because the user went to click the close button . The standard message box also has this masking treatment
  • MsgFm consists of 3 control areas, which are main message district、 Button area、 Detailed information area
    • main message district be A single control:MessageViewer, Directly inherited fromControl write as。 at the outset be Consider using an off-the-shelfLabel a control (e.g. button, text box etc) (computing), However, it was found that the latter's graphic mixing effect was not satisfactory( Don't talk about what the idiom meant), it be Cover the text directly on the icon, hehe, Presumably the writer of this control intended it be to beImage whileBackgroundImage use, So I had to write another oneMessageViewer。MV Two main things were done, protract( icons and text)+ Depending on the content identify Size of yourself, It also controls the minimum height, Avoid the icons and text being drowned out as a whole
    • The button area consists of a container class control, PanelBasic, holding up 4 buttons . PB is also inherited from Control, did not directly choose the reason for Panel, mainly Panel will be set when the Dock jump, the root cause of the specified parameters in the Control .SetBoundsCore notify the needless information, so simply inherit directly from Control to rewrite the method, by the way, to deal with the message, to solve the problem of instantaneous flash, the specific reason here is not detailed, the notes have a short description, in short, believe that I am not egg on the line . In addition, the button area controls the minimum width according to the visibility of the button, which, together with the minimum height of the MessageViewer above, constitutes the minimum size of the entire dialog box MinimumSize
    • PanelBasic on4 buttons be【 Detailed information】 buttons and others3 dialog command button。 The button is based on the incoming buttonMessageBoxButtons Parameters are processed dynamically( Button text、 be deny can be seen as), There's nothing to say.。【 Detailed information】 buttons(ToggleButton) And it took a lot of work., The button can be seen from its appearance not be standardButton, In fact it be toolbar buttons:ToolBarButton, belongToolBar onItem, Not in itself be A stand-alone control( Directly inherited fromComponent)。 It's a little bit here, As a result of . net 2 .0 riseMS It is recommended to use a new styleToolStrip substitute forToolBar, SimilarlyMenuStrip substitute forMainMenu、StatusStrip substitute forStatusBar、ContextMenuStrip substitute forContextMenu,VS2010 more be These are not displayed in the toolbox by default“ a control (e.g. button, text box etc) (computing)”( Some do not count as controls), So I guess I don't know much about the new children's shoes。 The latter are all be Nativewin32 subassembly, The former is purely .net Implemented, YesOffice2003 Control style。 In short, for therewin32 native For the control me, There is a special affinity for these old controls that are being suggested for replacement。 So this.ToggleButton in reality be By aToolBar and aToolBarButton composed of what looks like a single control, Then why is it still be Inherited fromControl rather than be Direct useToolBar this, I admit there's a reason for practicing your hands( I might write one later【 Teach you to encapsulate one step at a timeWin32 Native control】 article),Hmmm~ That's why, But it increases the amount of code, But be sure to believe that performance is no better than direct useToolBar difference, It's better in theory, because as a completeToolBar,MS There are quite a few things to consider, Obviously there is no less to deal with, And I'm thisToggleButton Because only one single button is responsible for the function, So it's actually verySimple veryLite~ You're smart enough to understand.。 In the end, why go to the trouble of making itToolBarButton rather than be It's straightforward to use aButton, It's because I've got my eye on mstsc .exe This effect of the:
  • A question remains, There is also a confession in this note, just (emphasis) be while main message When the text is very, very large ~ about the entire screen (this is actually incorrect posture, as mentioned above, a large amount of information should be put in the details area), if the dialog box is repeatedly dragged, expanded/closed, then at a certain time when the expansion, TextBoxUnSelectAllable will instantly flash in the main message area, this problem is perfectly solved in PanelBasic, but TextBox really can not do anything about it, tried to use the native Edit control directly, so leave it for now, there is no life without flaws!
  • Regarding sound, since the MessageBeep API is silent on srv08 systems, the PlaySound API was used instead . Also, make the otherwise silent MessageBoxIcon .Question rub the sound of SystemIcons .Information, which cannot discriminate against peopleQuestion
  • Finally.【 Detailed information】 The two icons on the button( unfold、 Put away one each) be I drew it, I wanted to pick it upmstsc .exe on, But it turned out to be less than satisfactory, It's better to draw it yourself

Having said all that, what I thought was an ideal implementation probably slotted in quite a bit, so again, I'd appreciate any pointers from passing warriors, thanks .

Finally. Demo is here There's a Tester inside for you to experience .

-Bunbi-


Recommended>>
1、The original version of the software is a good one
2、Chinas first embedded artificial intelligence vision chip released
3、IOST Zhong Jiaming there are tradeoffs in doing public chains open source lockin after IOST to really achieve the landing
4、Times Chain TCC Project Progress Weekly Report
5、Global chain bigwigs gather at Trusted Blockchain Summit 2018 in October

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号