Handling the Popup event raised by the System.Windows.Forms.ToolTip component would seem offer an ideal opportunity to alter the tooltip text to reflect an underlying change. Unfortunately the stack overflow caused by calling ToolTip.SetToolTip will soon put a stop to the attempt.
The test programme to investigate this issue creates a form containing two buttons, one of which will have dynamic tip strings. These are randomly selected from an array by the NewTipText method.
public partial class Form1 : Form {
ToolTip toolTip1;
String[] tipText;
Random rnd;
Boolean recursionBreak;
public Form1() {
InitializeComponent();
InitialiseToolTips();
tipText = File.ReadAllLines(@"..\..\Form1.cs");
rnd = new Random();
}
private void InitialiseToolTips() {
toolTip1 = new ToolTip();
toolTip1.SetToolTip(button1, "Fixed text");
toolTip1.SetToolTip(button2, "Variable text");
toolTip1.Popup += toolTip1_Popup;
recursionBreak = false;
}
private String NewTipText() {
Int32 idx = rnd.Next(0, tipText.Length);
return tipText[idx];
}
private void toolTip1_Popup(object sender, PopupEventArgs e) {
Debug.Print("POPUP {0}", e.AssociatedControl.Name);
if (recursionBreak) {
Debug.Print(" BREAK");
return;
}
if (e.AssociatedControl == button2) {
String proposed = NewTipText();
Debug.Print(" NEW TEXT '{0}'", proposed);
if (String.IsNullOrEmpty(proposed)) {
Debug.Print(" CANCELLED");
e.Cancel = true;
} else {
ToolTip tt = (ToolTip)sender;
if (proposed != tt.GetToolTip(button2)) {
recursionBreak = true;
tt.SetToolTip(button2, proposed);
recursionBreak = false;
} else {
Debug.Print(" UNCHANGED");
}
}
}
}
Preventing Recursion
SetToolTip reraises the Popup event internally when it is called from within the event handler and unless steps are taken to break this cycle a stack overflow is inevitable. In the example the boolean recursionBreak takes care of this although temporarily detaching the event handler would have the same effect.
tt.Popup -= toolTip1_Popup;
tt.SetToolTip(button2, proposed);
tt.Popup += toolTip1_Popup;
The Event Conundrum
Setting a control's tooltip dynamically requires a popup event, but the popup events for the control will stop if SetToolTip is called with an empty string argument. When NewTipText() returns an empty string, the tooltip display is suppressed by setting e.Cancel to true, and crucially SetToolTip is not called thus ensuring that events will continue to be raised.