ArticleDirectory
- Control and cueinfo
- About the ComboBox control
- Apply the watermark effect to the control.
It took some time to package a simple sendmessage and create a component for watermark management. Let's take a look at it first.
These two classes are the main types for implementing the watermark manager, namely cuer and cueinfo. Cuer is what I call the watermark manager. to distinguish it from DIY, it is not called watermarkmanager. Cueinfo saves the watermark information, including text and an option.
First, cueinfo has two main attributes: Text and hideonfocus, which are the watermark text, hideonfocus indicates whether to hide the watermark text when the control obtains the focus. The default value is true. For the other two attributes, control indicates the control on which the current cueinfo is applied, and manager indicates the cuer component that manages the current cueinfo. These two attributes are read-only and maintained by the cuer component.
All functions of the Win32 watermark manager are implemented by the cuer class. It inherits from component and implements the iextenderprovider interface. Below is a brief description of several members of the cuer component.
Public static bool issupported (control );
The function of this method is to test whether the specified control is supported by the cuer component. Because em_setcuebanner messages only support the Textbox Control, currently only textbox and ComboBox controls are supported.
Public void setcue (Control, cueinfo cue );
Its function is to specify watermark information for the control, including text content, and whether to hide it automatically.
Public cueinfo getcue (control );
Obtains the corresponding watermark information based on the specified control. If no watermark information is found, a null value is returned.
Public bool enabled {Get; set ;}
I don't want to mention this attribute. When it is set to false, all watermark information disappears.
Let's take a look at the following example. Assume that there is a form for user login, and there are two controls, one is the tbusername used to enter the user name, and the other is the tbpassword used to enter the password, set the text "User Name" and "password" as their watermark text respectively. See the followingCode.
Cuer cuer1 = New Cuer ();
cueinfo cue = New cueinfo ();
cue. text = " User Name " ;
cuer1.setcue (tbusername, cue);
cue = New cueinfo ();
cue. text = " password " ;
cuer1.setcue (tbpassword, cue);
Isn't it easy? A few simple lines of code can achieve the watermark effect. Now I have explained the two main classes cuer and cuerinfo. Next I will explain several key issues in the implementation details of this component.
Control and cueinfo
This is not hard to understand, because cuer operates outside of control. To match control with cueinfo one by one, you must use a dictionary with control as the key and cueinfo as the value, I use the generic dictionary class dictionary <control, cueinfo>. Dictionary maintenance is mainly completed in the setcue method. If the value of the cue parameter is null, it is removed from the dictionary. If it is not null, it is added to the dictionary. However, things are not that simple. There are some additional issues to consider when operating the dictionary. Think about the control and manager attributes of cueinfo mentioned above, these two attributes are maintained by cuer. Therefore, they must be maintained at the same time when being added or removed.
The setcue method checks whether the cue parameter has been managed (that is, the cueinfo. Manager attribute is not empty). Whether managed by the current cuer component or not, invalidoperationexception is thrown. Without such restrictions, several controls may share a cueinfo instance. Modify the previous example and refer to the following code:
Cueinfo cue = New Cueinfo ();
Cue. Text = " User Name " ;
Cuer1.setcue (tbusername, cue );
Cue. Text = " Password " ;
Cuer1.setcue (tbpassword, cue );
SuchProgramIn the end, should this cue variable represent the user name or password? Well, all I can think of is that the watermark text of passowrd is displayed in both input boxes. I don't know if this restriction will affect the actual application, at least I have never encountered any trouble when writing a demo.
It seems that the corresponding relationship should be relatively reliable, but the dynamic removal of controls is not considered. If the controller needs to be removed from the form for some reason during runtime, a useless Control Reference will be retained in the dictionary, although it may not cause too much impact, but it makes the program look less rigorous. Control. the disposed event can notify us that the unmanaged resource of the control has been released. In a sense, it is called, you only need to capture this event and remove it from the dictionary in the handler. For more information, seeSource codeThe setcue method and control_disposed method in.
About the ComboBox control
As I mentioned earlier, em_setcuebanner only supports textbox controls, but why does it support ComboBox? As mentioned in my previous article, ComboBox will actually embed a native edit control, that is, a Textbox Control, in the interior. As long as you can obtain this edit control, you can also use this API to implement the watermark function. However, it is a pity that ComboBox has three styles (dropdownstyle): simple, dropdown, and dropdownlist, which allow users to input text in the control, the third type is a pure drop-down list, which cannot be input. Therefore, there is no Edit Control in it, so the watermark function cannot be implemented on the dropdownlist ComboBox. But I think this is okay, because there is no watermark prompt for the drop-down list, which is not that important anymore.
As for how to obtain the internal Edit Control of ComboBox, the previous program is too simple to process. here we need to modify it first. Let's look at the code first:
Private Static Bool Getchildcallback (intptr hwnd, Ref Intptr lparam)
{
Stringbuilder clsname = New Stringbuilder ( 1024 );
Getclassname (hwnd, clsname, clsname. capacity );
If ( String . Compare (clsname. tostring (), " Edit " , True ) = 0 )
{
Lparam = Hwnd;
Return False ;
}
Return True ;
}
This is the callback function of enumchildwindows. During this callback process, you must determine whether the control represented by the handle being enumerated is edit. The API function getclassname can get the class of the window represented by the handle. If it is edit, it indicates that this is a textbox and false is returned directly to terminate subsequent enumeration. The reason for this is that when the ComboBox style is set to simple, two subwindows will be generated inside the ComboBox, And the edit position is 2nd, therefore, the results returned by the original method are certainly incorrect.
Apply the watermark effect to the control.
The first thing to grasp is the timing, that is, when to apply the watermark effect. I found a total of five times to apply the watermark effect:
- In the setcue method, after cueinfo is added to the dictionary, the watermark is applied to the control.
- When the value of the text attribute or hideonfocus attribute of cueinfo is changed and cueinfo is managed by a cuer.
- When the value of the cuer. enabled attribute is changed, all cueinfo that is being managed (that is, in the dictionary) will be applied again.
- After the handlecreated event of the managed control occurs, apply the watermark again.
The last case should be highlighted here. The handlecreated event occurs after the control's handle is created. This event is required in two cases. One is that the control's handle has not been created when the setcue method is called, you can use control. the ishandlecreated attribute is detected because the control has not been loaded, and the handle has been re-created when the control has been loaded. The second case is terrible, because it will cause the watermark to be unable to be displayed, which I have encountered during development. The default dropdownstyle of ComboBox is dropdown. If it is set to simple, the control's handle is re-created. If this event is not captured, the watermark becomes invalid.
The time is found, and the next step is to do the work. Call sendmessage to send the em_setcuebanner message and apply the watermark information to the control. The em_setcuebanner message has two parameters. When wparam is 0, the watermark is automatically hidden when the control receives the focus. 1 indicates that the watermark is hidden only when the user starts inputting the message. Lparam is the text to be displayed, which does not need to be explained. Cuer. applycue is used to implement this function. First, obtain the control handle Based on the specified cueinfo. If the handle value is not intptr. zero, convert the values of the text and hideonfocus attributes of cueinfo to lparam and wparam respectively, and then send messages. The gethandle method encapsulates the logic for obtaining the control handle. If the specified control is Textbox, the handle attribute is directly returned. If the control is ComboBox, the handle is obtained according to the method mentioned earlier.
So far, the article has explained several major issues about cuer implementation principles, followed by the development of functions supported during design. Considering that the article is too long and may cause reading fatigue, I will explain it again in another article. If you are interested, you can click here to download the source program and demo program, which is the demo program. (To explain, I plan to release this component to the codeproject, so I haven't written any text in the source code. Thank you for your understanding: d)
(To be continued)