Silverten
Silverten

Reputation: 31

In Windows Forms (C#) is there a way to set the tooltip's height and width dynamically

In Windows Forms (C#) is there a way to set the tooltip's height and width dynamically (meaning in code). I am working with a DataViewGrid control, so I am having to use the method Show. However, I have noticed (when left to it's own devices) that the tooltip control does not always adjust to the content provided....

An example:

Having a ToolTip control added to a form (called ttText) and then having it first show the text:

ttText.Show("I'm hungry\nand waiting!");  

will truncate the next call:

ttText.Show("Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!");

Any thoughts on this?

Keep in mind that a DataGridView requires a mechanism to display ToolTip help hence the use of the Show methods and I've seen this behavior elsewhere in non-DataViewGrids...

Here is an Example of code: using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms;

namespace TestForm
{
    class Form1 : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            this.ttText = new System.Windows.Forms.ToolTip(this.components);
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.SuspendLayout();
            // 
            // dataGridView1
            // 
            this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Location = new System.Drawing.Point(13, 19);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.Size = new System.Drawing.Size(453, 321);
            this.dataGridView1.TabIndex = 0;
            this.dataGridView1.CellMouseEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_MouseCellEnter);
            // 
            // ttText
            // 
            this.ttText.AutomaticDelay = 60;
            this.ttText.AutoPopDelay = 600000;
            this.ttText.InitialDelay = 60;
            this.ttText.IsBalloon = true;
            this.ttText.ReshowDelay = 60;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(478, 352);
            this.Controls.Add(this.dataGridView1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
            this.ResumeLayout(false);

        }


        private System.Windows.Forms.DataGridView dataGridView1;
        private System.Windows.Forms.ToolTip ttText;

        public Form1()
        {
            InitializeComponent();

            var ds = Sayings().ToList();

            dataGridView1.DataSource = ds;
        }

        public List<dynamic> Sayings()
        {
            return new List<dynamic>
            {
                new 
                { 
                    Human = "I'm hungry\nand waiting!",
                    BabyBear = "Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!"
                }
            };
        }

        private void dataGridView1_MouseCellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != -1 && e.RowIndex != -1)
            {
                var rect = dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
                var left = rect.Left + (int)(rect.Width * .5f);
                var top = rect.Top;

                Point displayPoint = new Point(left + this.ClientRectangle.Left, top + this.ClientRectangle.Top + 40);

                ttText.Show(dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString(), this, displayPoint);
            }
        }
    }
}

If you hover over the 1st column, then the second, the the tool tip text gets truncated.

Upvotes: 1

Views: 5844

Answers (3)

IV.
IV.

Reputation: 9511

What worked for me to avoid truncating the tool tip is to set the ToolTip text explicitly. What I think is subtle is that the default ToolTip text uses the same cell content, only the default handler does truncate it as noted in the original question. By overriding the event and setting the ToolTip text (even though it's exactly the same cell text!) now the default length restriction seems to go away.

protected override void OnCellToolTipTextNeeded(DataGridViewCellToolTipTextNeededEventArgs e)
{
    if((e.RowIndex >= 0) && (e.ColumnIndex >= 0))
    {
        // By setting this explicitly we can make the ToolTip show the           
        // entire length even though the content itself has not changed.
        e.ToolTipText = this[e.ColumnIndex, e.RowIndex].Value.ToString();
    }
    base.OnCellToolTipTextNeeded(e);
}

Upvotes: 0

Silverten
Silverten

Reputation: 31

OK, it has been several months now since I posted this question. I haven’t really given this problem any thought since then – just accepted the behavior... until tonight.

Since no-one else thought of an answer (or cared to provide an alternative Window Forms idea), it occurred to me to re-look at the general problem. The balloon tool tip seems to be a free-form kind of thing... It takes the previous shape it encounters. It's probably Microsoft's laziness at work. Or better – it's Microsoft's way of pointing developers in a different direction. After all, the only new direction provided was towards wpf...

However, as I stated in the original question, I needed a solution that was ONLY windows forms, not mixing WPF or Silverlight or other technologies into the pot. After all, if you are a WPF programmer, you may want to add Windows Forms controls in to the mix, but for the purest, this won't do.

So here is a bit more to the solution to the puzzle – how to make a balloon resize to the dimensions desired...

I re-looked at the problem and noticed that the balloon would resize each time the mouse pointer entered into the cell, so to that end, the following was derived:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace TestForm
{
    class Form1 : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            this.ttText = new System.Windows.Forms.ToolTip(this.components);
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.SuspendLayout();
            // 
            // dataGridView1
            // 
            this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
            | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Location = new System.Drawing.Point(17, 23);
            this.dataGridView1.Margin = new System.Windows.Forms.Padding(4);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.Size = new System.Drawing.Size(604, 395);
            this.dataGridView1.TabIndex = 0;
            this.dataGridView1.CellMouseEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_MouseCellEnter);
            this.dataGridView1.MouseLeave += new System.EventHandler(this.dataGridView1_MouseLeave);
            this.dataGridView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.event_MouseMove);
            // 
            // ttText
            // 
            this.ttText.AutomaticDelay = 0;
            this.ttText.AutoPopDelay = 0;
            this.ttText.InitialDelay = 10;
            this.ttText.IsBalloon = true;
            this.ttText.OwnerDraw = true;
            this.ttText.ReshowDelay = 0;
            this.ttText.ShowAlways = true;
            this.ttText.UseAnimation = false;
            this.ttText.UseFading = false;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(637, 433);
            this.Controls.Add(this.dataGridView1);
            this.Margin = new System.Windows.Forms.Padding(4);
            this.Name = "Form1";
            this.Text = "Form1";
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.event_MouseMove);
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
            this.ResumeLayout(false);

        }

        private System.Windows.Forms.DataGridView dataGridView1;
        private System.Windows.Forms.ToolTip ttText;

        public Form1()
        {
            InitializeComponent();

            dataGridView1.ShowCellToolTips = false;
            var ds = Sayings().ToList();

            dataGridView1.DataSource = ds;
        }


        public List<dynamic> Sayings()
        {
            return new List<dynamic>
            {
                new 
                { 
                    Human = "I'm hungry\nand waiting!",
                    BabyBear = "Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!"
                },
                new 
                { 
                    Human = "What a selfish bear!\n\n\nAt least you could do is wait for\nothers to join you!",
                    BabyBear = "Boo Hoo!"
                },
                new 
                { 
                    Human = "Oh, I'm sorry!",
                    BabyBear = "Now, I'm going to eat you!"
                },
                new 
                { 
                    Human = "\n\n\n!!!\n\nWhat?????\n\n\n\nI don't think so!\n\n(Human pulls out Honey Jar)",
                    BabyBear = "Yum!"
                },

            };
        }

        private void dataGridView1_MouseCellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != -1 && e.RowIndex != -1)
            {
                this.SuspendLayout();

                var rectC = dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
                var left = rectC.Left + (int)(rectC.Width * .5f);

                var rectR = dataGridView1.GetRowDisplayRectangle(e.RowIndex, true);
                var top = (rectR.Top + (int)(rectR.Height * .5f));

                Point displayPoint = new Point(left + this.ClientRectangle.Left, top + this.ClientRectangle.Top + 40);

                var column = e.ColumnIndex;
                var row = e.RowIndex;

                for (int i = 0; i < 5; ++i)
                {
                    ttText.Show(dataGridView1[column, row].Value.ToString(), this, displayPoint);
                    ttText.Hide(this);
                }
                ttText.Show(dataGridView1[column, row].Value.ToString(), this, displayPoint);

                this.ResumeLayout();
            }
        }

        private void dataGridView1_MouseLeave(object sender, EventArgs e)
        {
            Rectangle mouseRect = new Rectangle(MousePosition, new Size(1, 1));

            var rectC = dataGridView1.GetColumnDisplayRectangle(dataGridView1.Columns.Count - 1, true);
            var right = rectC.Right;

            var rectR = dataGridView1.GetRowDisplayRectangle(dataGridView1.Rows.Count - 1, true);
            var bottom = rectR.Bottom;

            var rect = new Rectangle(
                dataGridView1.PointToScreen(dataGridView1.Location),
                new Size(right, bottom));

            if (!rect.IntersectsWith(mouseRect))
                ttText.Hide(this);
        }

        void event_MouseMove(object sender, MouseEventArgs e)
        {
            dataGridView1_MouseLeave(sender, EventArgs.Empty);
        }
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

I have expanded the narrative in the grid to help demonstrate the general problem.

I know that this is not a completely elegant solution – but that's what encapsulation is all about.

The new problem... Is it possible to have the point of the balloon tool tip be displayed at the mouse point – or am I just living a pipe dream?

Now, as far as a possible solution... I have read a bit about inheriting the Tool Tip object to perform drawing with a custom class. Is it not feasible to use that to determine the size of the text, and then determine which direction the balloon would display and the offset of the text?

Upvotes: 2

ScottJShea
ScottJShea

Reputation: 7111

On MSDN it mentions using the RenderSize property for this sort of thing but with some caveats.

Upvotes: 0

Related Questions