Click here to Skip to main content
Click here to Skip to main content

Building a BallonToolTip provider in C#

By , 3 Mar 2004
 

Sample Image - BallonTipExample.jpg

Introduction

The System.Windows.Forms namespace includes a built-in class for displaying tooltips on a control. However, this ToolTip control does not support creating the cute balloon tooltips that are available with IE 3.0 and above. This class provides a managed wrapper for the Win32 Tooltip common control that supports displaying Balloon Tool Tips.

Using the Control

The control provides functionality exactly like the current ToolTip provider that ships with .NET. To use it on a form or control, you simply drag an instance of the control onto the form from the Visual Studio .Net toolbox. Once added, each control on the form will have a new ToolTip property that you can set for the particular object. Visual Studio will automatically add the needed code to hook the control's tooltip to the BallonToolTip provider.

API

The API consists of the same properties and methods as the standard ToolTip class that the .NET Framework provides. Each instance of the BallonToolTip class can support tool tips for several controls. To set the tooltip for a control, you use the SetToolTip method:

public void SetToolTip(Control control, string tooltip)

Similarly, to retrieve the tooltip for a given control, use the GetToolTip method:

public string GetToolTip(Control control)

Designer Support

Like the ToolTip class, the BallonToolTip class includes support for setting tooltips at design time. Adding this support for any property is relatively easy. First, the class must derive from System.ComponentModel.Component. Second, the class must be decorated with ProvideProperty attribute and implement the IExtenderProvider interface. The ProvideProperty attribute provides the designer with the name and type of the property that should be added to any control that the IExtenderProvider.CanExtend method returns true for. These two elements work together to support providing a ToolTip property for each control on a form. The BallonToolTip class is declared as follows:

[ProvideProperty("ToolTip", typeof(Control))]

public class BallonToolTip : Component, IExtenderProvider

There are a few tricks to using the ProviderProperty attribute. For one, the class it is added to must provide both GetX and SetX methods, where X is the name of the property passed to the ProvideProperty attribute. Also, your GetX method should be decorated with a DefaultValue attribute to reduce the amount of code the designer has to create. In the case of the BallonToolTip provider, the GetToolTip method is decorated as follows:

[DefaultValue("")]
public string GetToolTip(Control control)

Annoyingly, when SetToolTip is called from the InitializeComponent method of the class the tooltip is present on, the controls may not yet have handles. To handle this case, the BallonToolTip control hooks the HandleCreate event of the Control base class when any control is passed to SetToolTip. When this event fires, the tooltip provider automatically updates the underlying Win32 tooltip window with the information for the newly created control. For completeness, the SetToolTip method also hooks the HandleDestroyed event to delete the native tooltips when a control is destroyed (in a typical form, this is not really an issue, since the control will be destroyed more or less at the same time as the provider).

Using the NativeWindow class

A little known class in the System.Windows.Forms namespace is the NativeWindow class. This class' one and only goal is to provide a managed wrapper around the Win32 CreateWindowEx function. In the BallonToolTip method, I have created a derived NativeWindow class (NativeTooltipWindow) that provides a few useful wrappers around this class. For example, NativeTooltipWindow builds the CreateParams structure used to create the native ToolTip provider without input from outside classes. This way, knowledge about how to create the window is enclosed in the class that actually does the creation (see the source code for additional comments and information).

Supporting Win9X

When sending messages to the underlying Win32 Tooltip window, some messages are required to send different values based on whether we are running on a Windows 9x machine (which uses ASCII based text) versus a NT based system (which uses Unicode). During the construction of the class, we set up the readonly ints to make dealing with this difference easier in the code:

private const int TTM_ADDTOOLA = 1028;
private const int TTM_ADDTOOLW = 1074;
private const int TTM_UPDATETIPTEXTA = 1036;
private const int TTM_UPDATETIPTEXTW = 1081;
private const int TTM_DELTOOLA = 1029;
private const int TTM_DELTOOLW = 1075;

private readonly int TTM_ADDTOOL;
private readonly int TTM_UPDATETIPTEXT;
private readonly int TTM_DELTOOL;

/// <SUMMARY>
/// Initializes a new instance of the
/// <SEE cref="ToolTipLibrary.BallonToolTip" /> class.
/// </SUMMARY>
public BallonToolTip()
{    
    m_controls = new Hashtable();
    m_active = true;
    m_showAlways = false;

    //Create a new native window.
    m_window = new NativeTooltipWindow();

    if (Marshal.SystemDefaultCharSize == 1)
    {
        //Win9x machines
        TTM_ADDTOOL = TTM_ADDTOOLA;
        TTM_UPDATETIPTEXT = TTM_UPDATETIPTEXTA;
        TTM_DELTOOL = TTM_DELTOOLA;
    }
    else
    {
        //WinNT machines
        TTM_ADDTOOL = TTM_ADDTOOLW;
        TTM_UPDATETIPTEXT = TTM_UPDATETIPTEXTW;
        TTM_DELTOOL = TTM_DELTOOLW;
    }

    InitializeComponent();
}

In the code, we never use the constants above. Instead, we always reference the readonly member variables to ensure we are sending the right message for the platform.

Changes

3/4/2004 - Fixed a bug in the CreateHandle method to create the tooltip handle when it does not exist.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

wilsone8
Software Developer (Senior)
United States United States
I've been a software engineer since 1999. I tend to focus on C# and .NET technologies when possible.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalfind which control is shownmemberhamid_m7-Aug-07 4:25 
i want add some code for fixe move ballon when form is moveing
in your class i add an event, but how can i find witch control is on proccessing?
GeneralHELP C# :Button User control and Tooltipmembercrazychris6420-Jul-07 3:40 
Hello, i would like to put a tool tip on a button user control.
Code C#:
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
 

namespace Gso.Siati.WinApp.UserControls
{
//public partial class SButton : UserControl
public partial class SButton : Button
{
private IContainer components;
private ToolTip toolTip1;
private Button button1;

public SButton()
{
InitializeComponent();
}
 
public string ToolTip
{
get
{
return this.toolTip1.GetToolTip(this.button1);
}
set
{
this.toolTip1.SetToolTip(this.button1, value);
}
}
 
private void SButton_Load(object sender, EventArgs e)
{
 
}
 
private void button1_Click(object sender, EventArgs e)
{
 
}
 
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.button1 = new System.Windows.Forms.Button();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// button1
//
this.button1.AutoEllipsis = true;
this.button1.Location = new System.Drawing.Point(0, 0);
this.button1.MaximumSize = new System.Drawing.Size(96, 32);
this.button1.MinimumSize = new System.Drawing.Size(96, 32);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(96, 32);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click_1);
//
// toolTip1
//
this.toolTip1.IsBalloon = true;
this.toolTip1.OwnerDraw = true;
this.toolTip1.ShowAlways = true;
//
// SButton
//
this.Size = new System.Drawing.Size(96, 32);
this.ResumeLayout(false);
 
}
 
private void button1_Click_1(object sender, EventArgs e)
{
 
}
}
 
}
 
When i put this.buttonClose.ToolTip = "test"; in an other file, i can't see the tool tip "test" on my button close.
 
Help me please...

Questionhelp me plzmembermr nasr6-Feb-07 21:50 
i want to use from rightToLeft ballon -how can i do it?
 
r.n

GeneralUsing in commercial applicationmemberescristian18-Sep-06 5:32 
Hello, I just wanted to know if it's ok for me to use your tooltip in a commercial application. Untill my boss decides to move to 2005 I'm kind of stuck, and I need a way to show a tooltip in code.
 
So what I would do is use your tooltip and set the ShowAlways property to true when I need it.
 
Thanks, Cristian Santayana.
GeneralRe: Using in commercial applicationmemberwilsone818-Sep-06 9:38 
Of courseSmile | :) Feel free to use this code anywhere you wish.
Generaldoesn't work on .NET 2.0memberSLoW_Ru28-Feb-06 20:01 
i've added ballontipprovider on a form, set property active to true, called settooltip... but there's NO tooltip! and ach component on my form have NO property tooltip.
what is wrong
GeneralRe: doesn't work on .NET 2.0memberwilsone87-Mar-06 9:18 
In .NET 2.0, the Microsoft ToolTip provider already supports ballon tooltips.
GeneralIcon and Titlememberasgerb27-Sep-05 2:42 
Any ideas on how to set the Icon and Title. I tried setting it up the same as for the multiline, but seem to be getting outofmemory errors.
Jokemultiline supportmemberkilroytrout30-Aug-05 11:27 
You can add multiline support to this code by adding a property to BallonToolTip.cs that sets the maximum tool tip width. The native control will then automatically add line breaks as needed. To do this send the TTM_SETMAXTIPWIDTH message (1048) to the native control handle. I added a property that calls this for its set method:
 
NativeMethods.SendMessage(m_window.Handle,TTM_SETMAXTIPWIDTH,0,m_toolTipWidth);
 

GeneralRe: multiline supportmemberseishin6667-Nov-06 0:44 
I'd prefer to use \n\r or Enviroment.NewLine.. is there a way for that?
QuestionBut can you make them go away?membersam898837823-Jun-05 10:10 
Sure, balloon tooltips have their place. Unfortunately what is the user to do when they think their place is everywhere? If you enter "balloon tips" "tooltips" or even "popup tips" in the microsoft xp forum, you'll see that more people than just myself find them distracting & wish they would go away.
 
Unfortunately microsoft, with it's usual customer empathy, decided to make them non-optionalMad | :mad: . While that alone is a good reason for learning Linux, its kind of time intensive (not to mention the potential for disaster for the unskilled) to have to adapt everything to a new system.
 
So here is the question: if you can program IN tooltips, can you program them OUT?
Confused | :confused:
 
sam8988378
AnswerRe: But can you make them go away?memberwilsone87-Mar-06 10:44 
Um...don't add my control to your project?
GeneralRe: But can you make them go away?membersam89883789-Mar-06 8:40 
Laugh | :laugh: If only it were that simple! Windows xp breeds tooltips like rabbits, and they are harder to kill than Jason VoorheesMad | :mad: .
 
Fortunately, Peregrine Falcon's code http://www.codeproject.com/tools/killtt.asp#xx1239801xx completely eliminated all tooltips from winddows media player and most of xp Smile | :)

 
sam8988378
QuestionMultiline?memberBigAndy8-Jun-05 5:55 
Is there a way to have multiline tooltips? I've tried just adding \r\n where required, but it just renders on one line. Any ideas?
GeneralMultiLinememberphongta20-Nov-04 3:17 
Is it possible to display multiline tip ? Thz,
 
Phong
GeneralBefore displaying the ToolTipmembermasontwo2-Sep-04 11:37 

I was wondering if there was anyway to get an event just before the window is displayed. I need to change the text of the tooltip depending on the item that I happen to be hovering over. Any help would be appreciated
 
Masontwo
Generallittle errormembernadia.giusti3-Mar-04 0:25 
To run succesfully the code is necessary to modify the following:
private void CreateWindowHandle(Control control)
{
   if (m_window.IsHandleCreated)
      ....
}
 
in
private void CreateWindowHandle(Control control)
{
   if (!m_window.IsHandleCreated)
      ....
}
 
Regards
nadia giusti
GeneralRe: little errormemberwilsone84-Mar-04 11:05 
Thanks for the note. I apparently uploaded an early build of the code that did not have that fix in it. Smile | :)
Questionwhat's WrOng ?memberMustafa DÜLGERLER27-Feb-04 2:28 
I added the control to the Form. Controlled its Active parameter was set TRUE by default. first i set "Show Always" parameter to False. Then in Design Mode, i set "ToolTip on BallonToolTip1" property of a button to "Button1 ToolTip" and for run time code, i wrote "BallonToolTip1.SetToolTip (PictureBox1, "me Smile | :) ")" in Button2.Click Event. But both of them were not run. Then I ask What's wrOng?

 
Mustafa DÜLGERLER
Young developer Smile | :)
AnswerRe: what's WrOng ?memberwilsone84-Mar-04 11:05 
The original code contained a bug. I have uploaded the correct code, and everything should work fine.
Generalany sample projectmemberthmok27-Feb-04 1:17 
Look very interesting, but how to use it ??OMG | :OMG:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 4 Mar 2004
Article Copyright 2004 by wilsone8
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid