|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionEveryone knows the ToolTip control (the programmer ones!!) which are included in the Common Controls version 4.0 since Win95 (that’s what saw first, I haven't ever caught the Win3.11). Since then the control itself have been modified and enhanced in many ways, and after a while, WinXP came to life and the Common Controls version 6.0 saw light with the Balloon ToolTip control included, which is the subject of this article. Neither creating a Balloon ToolTip nor implementing an While searching around, I found a great article about the Balloon ToolTip control (actually about the BackgroundReading this article would give you a general understanding of the basic ideas discussed here, but to have a complete understanding of every concept, you must have some knowledge of the Win32 API calls and their uses. You don't have to be a professional to get it right and shouldn't be a fresh guy either (you shouldn't have to jump to the nearest programming book you have to figure out what is the Win32 Using the codeAfter this heavy theoretical talk, we can start getting our hands dirty. The IExtenderProvider InterfaceThe This interface provides a single method For almost any control that implements the public bool CanExtend(object extendee)
{
if(extendee is control && !(extendee is BalloonToolTip)
&& !(extendee is From))
{
return true;
}
return false;
}
Based on the result of this call, the VS designer, or any other third-party designer used, decides whether to provide the specified service to the control or not, so when you select a control, the designer calls this method at design time, passing the selected control to it as a parameter, and if its get The ToolTip ControlThe ToolTip control is somehow confusing while reading about it in the MSDN, and to get it right, you should distinguish between two concepts, the That's it. You create the As with any other control, by supplying the IntPtr toolwindow;
Toolwindow = CreateWindowEx(0, “tooltips_class32”, string.Empty,
WS_POPUP | TTS_BALLOON | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, IntPtr.Zero, 0, 0, 0);
The most important of these constants is the Other DetailsFor now, we have a The
This summarized list is by no means a reference to the messages that the The Take a look at the typedef struct tagTOOLINFO { UNIT cbSize; UNIT uFlag; HWND hwnd; UNIT_PTR uId; RECT rect; HINSTANCE hinst; LPTSTR lpszText; #if(_WIN32_IE >= 0x0300) LPARAM lparam #endif }TOOLINFO This structure represents a tool contained in a Leaving The Managed WorldIf you have to deal with unmanaged code like these Win32 API calls, let me introduce you to a good friend, the // first we have to construct a managed toolinfo structure
toolinfo tf = new toolinfo;
// now specify the size of this structure in the size member
tf.size = Marshal.SizeOf(typeof(toolinfo));
// specify how the balloon window should be displayed
tf.flag = TTF_SUBCLASS | TTF_TRANSPARENT;
// associate the structure with the target control (the one on your form)
tf.parent = targetcontrol.Handle;
// specify the text you want to be displayed
tf.text = “Tooltip text to be displayed”;
// we need a temporary pointer to hold our unmanaged copy of TOOLINFO object
IntPtr tempptr;
// now allocate enough memory to hold this structure in the unmanaged heap
tempptr = Marshal.AllocHGlobal(tf.size);
// copy the content of our filled managed
// TOOLINFO object to the newly allocated memory space
Marshal.StructureToPtr(tf, tempptr, false);
// now send a message to our ToolTip control that we have a tool to be added
// and remember that our ToolTip is just a pointer return by CreateWindowEx
SendMessage(tooltipptr, TTM_ADDTOOL, 0, tempptr);
// now our tool have been added to the ToolTip control,
// and we have to clean out what we did
Marshal.FreeHGlobal(tempptr);
For those who started scratching their heads (asking what the hell was that?) if any, I'll just say that explaining about how to work with unmanaged code is beyond the scope of this article. Anything that seems to you to appear either in the Are We Done With The IExtender?As an answer, not yet. There is a little detail that's not been discussed yet. The [ProvideProperty(“BalloonText”, typeof(Control))]
public class BalloonToolTip : System.ComponentModel.Component,
IExtenderProvider
{
...
}
After adding this attribute, and when we add our control to the designer, every supported control on the form will have a new property added to its properties, named as the text specified in the Now we have done marking our class with its provided property name and receiver type, but this is still not enough from a code perspective. In our code, there must be a Get/Set pair of functions with exactly the same name as our extended property. To put it another way: we specified “ The Get function is a function that returns a string (surprised? !!) which is the string associated with the control passed to it as a parameter. This parameter must be the same type as the receiver type in the public string GetBalloonText(Control parent)
{
... // return the string associated with the tool
// that have its parent equal to the passed control.
}
And the Set function is a public void SetBalloonText(Control parent, string value)
{
... // Add the passed string to a new tool
// with its parent equal to the passed control.
}
These functions do not appear as ordinary functions in the code, but as properties in the control they have extended, so don't get confused (after all, that's what the The last thing to say is that it's your choice how to implement these functions. You may have a The hash table is a place to store a collection of key/value pairs, and in our case, we already have these key/value pairs. It's our control/property pair. For each control, we have a unique string as its For the Get function, there is nothing more to say, but for the Set function there is: public void SetBalloonText(Control parent, string value)
{
if(value == null)
value = string.Empty;
if(value == string.Empty)
// the user delete our property value,
// so he don’t want our service
{
hashtable.Remove(parent);
// remove our pair from the collection
... // create a toolinfo object, assign its parent
// member the handle of the passed control
// and send a message with TTM_DELTOOL
}
else
// the user has assigned our property a value,
// so he want our service
{
if(hashtable.Contains(parent))
// check whether we have added the control before or not
{
// if we did, then the user has just modified
// the property text, so update
// the hashtable and the tool
hashtable[parent] = value;
...
// create a toolinfo object, assign its parent member
// the handle of the passed control
// and send a message with TTM_UPDATETIPTEXT
}
else
{
// the user assign a new value to the property,
// so add it to the hashtable and add a new tool
hashtable.Add(parent, value);
...
// create a toolinfo object fill its
// values and send a message with TTM_ADDTOL
}
}
}
Congratulations, mission accomplished successfully! There are a couple of properties I have added to the control but I didn't mention any of it here, they are too simple to be explained. I tried to comment any interesting or important point in the code example. Points of InterestIf you take a look at the code example, you may wonder why I would add a new Simply, because if you omit this, the You may also note that I don't add any I hope that this article was useful to you.
|
||||||||||||||||||||||