Summary
1. Why do we need to provide a custom message box?
2. Let me talk about my general ideas.
3. Where are your highlights?
4. Are they all?
Download the project source package described in this article
What causes us to provide a custom message box?
This was initially due to the almost idiotic requirement of the Project Manager. One day, he told me that the pop-up message box was too small. I told him that this is something that comes with the system. The size automatically changes with the length of the given text. He said no, it's a little bigger and the font is too small. Change the font! My God, do architects never really writeCode?
It may be difficult to meet this requirement. First, let's see what interface the system gave me: MessageBox is located in system. windows. in the forms namespace, It is a static class that is sealed. The public method that can be used is MessageBox. show, there are many overloaded versions, but there is also an option parameter, but this parameter does not provide what I really are interested in.
I am still familiar with the problem. First, I would like to ask Google, and then I will go directly to codeproject or SourceForge to find the problem. General problems can be solved. Once we had such a demand, let's look at other people's solutions. Most people use hook, that is, system message interception, to obtain the handle of the message box, and then use winapi to tamper with some features of the form. There are many examples with distinctive features: you can add a ComboBox above to tell it don't show this in the next time; you can assign the text value you want for the button; you can also modify the font and font size attributes of some text;
It seems that this is the solution I want, because it can do almost everything. As a beginner in windows, I urgently need to hook it up. The problem is that, I found that no matter how I tried to modify the examples made by those authors using the hook, the final result is still: all vertices in the message box are eventually the same! That is to say, if you convert the text in the message text part into vadana, the text in the button will also change to vadana, which is actually one!
That's good. I just don't want to hook it. I have never succeeded in it. Other people can do it as an example. I just can't do it!
Let's just try it out. I'll try it myself.
Let me talk about my general ideas
It is not difficult to draw a form under. net. In fact, just drag the mouse down. The problem is that one thing always involves many other things.
OK, let's see what my own MessageBox really needs. What is actually needed is to try to imitate the message box that comes with the system as much as possible. It is best to replace it completely.
You must be able to customize the number of buttons and provide different prompt icons (errors, inquiries, information, etc.). It is best to make the corresponding system sound, after the message box disappears, obtain an enumeration value of the button. You must be able to specify a parent form (as the mode form on this page) for it and use it safely in non-UI threads. This is probably the case.
Number of custom buttons
The number of buttons will affect their location layout on the form. Therefore, you need to know the width of a single button and the location difference between two adjacent buttons.
InSource codeThe following enumeration is provided:
Public Enum Msgboxbuttons
{
/**/ /// <Summary>
///OK
/// </Summary>
OK = 0 ,
/**/ /// <Summary>
///OK and cancel buttons
/// </Summary>
Okcancel,
/**/ /// <Summary>
///OK, no, and cancel buttons
/// </Summary>
Oknocancel,
}
In most cases, this combination of buttons is sufficient.
I found that I could not get the default button size, so I made a hypothesis:
Const Int Defbtnwidth = 75 ; // Todo -- this may not be right
Const Int Gaptwobtns = 150 ;
Const Int Gaptribtns = 100 ;
The preceding section also contains the spacing values between buttons.
Custom error prompt icon
The purpose is to see at a glance what has happened: error? Prompt information? Question selection?
For this reason, I draggedImagelistComponents, embedded with a group of icons, and defined the following enumeration:
Public Enum Msgboxicons
{
// Note: notice the order, corresponds to their images 'order
/**/ /// <Summary>
///Success mark
/// </Summary>
Good = 0 ,
/**/ /// <Summary>
///Error mark
/// </Summary>
Error,
/**/ /// <Summary>
///Indicator
/// </Summary>
Info,
/**/ /// <Summary>
///Inquiry mark
/// </Summary>
Question,
/**/ /// <Summary>
///Do not show any logo
/// </Summary>
None,
}
Note that the enumerated values and
ImagelistInImageThe order is one-to-one. If you want to add your own icons, you should maintain this relationship.
Sound when a form is popped up
This function is completely imitated. Check the code.
Internal Static Void Dobeep (msgboxicons icon)
{
// Play the associated systemsound
Switch (Icon)
{
Case Msgboxicons. Error:
Systemsounds. Hand. Play ();
Break ;
Case Msgboxicons. Good:
Case Msgboxicons. Info:
Systemsounds. Asterisk. Play ();
Break ;
Case Msgboxicons. Question:
Systemsounds. Question. Play ();
Break ;
Default :
Systemsounds. Beep. Play ();
Break ;
}
}
ObtainDialogresultValue
This value is very important, and it will be fed back to the caller to help them make a corresponding decision. Here I directly useDialogresultEnumeration. Each button'sDialogresultValue.
Provide the parent form parameter
This is very simple.ShowdialogEach hasOwnerParameters. However, you will find that if you are inUIThread, so the call does not have any discomfort, you do not even need to provide ITOwnerParameter. The current form is used as the parent form by default. Everything works well.UIIn the thread, you cannot do this. See the following.
NonUIUse it in the thread
Assume that we have providedShowdialogMethod. In fact, I provide many heavy-load versions of this method, which is easier to use than the built-in system. In non-UIWhen using it in a thread, you have2Options:OwnerParameter or not provided; if not provided, it cannot match yourUIWhen the main form is connected, it is not blocked in front of any form and becomes the mode form above it, which makes people feel uncomfortable. I found that this problem should be solved in particular; then we can provide this parameter.HandleJust give it to me.ProgramOnly occasional work is allowed. We should all know that this is the problem of cross-thread access control. The original problem is that if you needADisplay a mode form on the formB, This task must be delegatedAFormUIThread execution is required! Please note that it takes a long time for me to clarify this point!
OK, You understand, you need a Commission to do this, very good, you areANon-UIDefine a delegate object in the thread code and use a method (BFormShowdialogMethod), and thenForma. Invoke ()To delegateAOfUIThread.
That's right. This is a standard solution. Everyone has always done this,. NetOfMsdnWe recommend that you do this. However, the message box we need is an independent component. Do you require every program that uses this component to provide a delegateUIIs such a message box displayed in the thread? Very troublesome, isn't it? I want to give youHandleYou are blocking thisHandleIn front of the form. As a result, this problem has become a challenge for this small project.
Where are your highlights?
This is the most important part of this article. It took me a long time to understand that I hope you just don't1Minutes to understand and remember.
As mentioned above,. NetThis cross-thread calling mechanism requires us to use the delegate to implement: If you needADisplay a mode form on the formB, Then delegate the taskAOfUIThread to execute!
When the delegate object is put on the caller side, it will bring additional encoding, so I put it into my own component, that is, this custom message box!
// Required for cross-thread use
Private Delegate Dialogresult showitdelegate (Form owner );
Private Static Dialogresult showit (Form owner, msgbox mbx)
{
If (Owner ! = Null
&& Owner. invokerequired)
{
Showitdelegate d= NewShowitdelegate (mbx. showdialog );
Return(Dialogresult) Owner. Invoke (D, owner );
}
Return Mbx. showdialog (owner );
}
Is that what it is?
In this way, your message box is indeed better than the system, you canUIConvenient to use under the thread, but it is also a very basic message boxHookThe example shows more attractive than yours.
That's right.HookThe example shows a lot of useful technologies: addComboBoxTo automatically disappear after the form is not clicked for a period of time (a defaultDialogresultValue) to replace the text font on the button.
But is all this a difficult problem for a form program completely developed by yourself? It's too simple. Of course, I have killed some things. In fact, if you want to get a highly customized featureShowMethod providesMsgboxoptionsThe source code is in your own hands. Nothing can be done!
Of course it depends on your needs. For me, this is enough. I have been using my own message box, which is too convenient! Like yourself first:-)
Postscript
Initially I usedSingletonMode, but in many places it may be required to pop up a form, and the previous form has not disappeared, which leads to a problem,. NetAn exception is thrown: The displayed mode form cannot be displayed again (in this case ). After self-observation, I found that the message box in the system is similar to the one created every time when needed, and then discarded. That is to say, each place in use is a new message box. So it evolved into the current version.
Thank you for reading prawns and cainiao. Have a good time!
(After the full text is complete, the page will provide the source code package for download)