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

Tagged as

Implementing Dynamic ToolTips: Preventing SetToolTip stack overflow

, 17 Feb 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
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...
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();
    // use this code file as the source of strings
    tipText = File.ReadAllLines(@"..\..\Form1.cs");
    rnd = new Random();
  }
 
  private void InitialiseToolTips() {
    toolTip1 = new ToolTip();
    toolTip1.SetToolTip(button1, "Fixed text");
    // initialisation of button2's tip is necessary
    // even though this text will never be shown
    toolTip1.SetToolTip(button2, "Variable text");
    toolTip1.Popup += toolTip1_Popup;
    recursionBreak = false;
  }
 
  private String NewTipText() {
    // randomly select a string from the array
    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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alan N
Engineer
United Kingdom United Kingdom
There were these two guys at work who programmed a product costing programme on the new Wang (10Meg Winchester). I looked at their spaghetti and thought uhh, what's going on there. That was while ago, as I see that the spiral bound Wang Professional Computer Series "Basic Language Guide" Third Edition, which I've just pulled off the bookshelf, was published in 1985.

Shortly after that "the corporation" upgraded to the heavenly Amstrad 1512's (20Meg). Paul and I cracked the password file and I was really keen on creating a key logger but decided that I wanted to keep my job instead.

Way before all of this my cousin had a computer and although I can't remember what make it was, it seems that his programming pinnacle was making the lights on it's front panel flash on and off. At the time I was more interested in Lego. Happy days.

Back to the Wang, if that not too rude a phrase, I remember that our IT professional programmed F1 to enter the mainframe password because no one knew what it was!

Most embarrassing computer moment... Having to admit that it was me who had typed del c:\*.*

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150414.1 | Last Updated 17 Feb 2010
Article Copyright 2010 by Alan N
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid