Click here to Skip to main content
15,893,401 members
Articles / Programming Languages / C#

Set TextBox Height

Rate me:
Please Sign up or sign in to vote.
3.92/5 (6 votes)
7 Sep 2008CPOL2 min read 153.5K   3.7K   25  
How to change the height of a single-line textbox
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

// Adjustable Height Text Box
// (c)Adrian Hayes, 2008.
// hayes.adrian@gmail.com
// * Source Code and Executable Files can be freely used in commercial applications;
// * Source Code can be modified to create derivative works.
// * No claim of suitability, guarantee, or any warranty whatsoever is provided. 
//   The software is provided "as-is".
// * If you publish the Source Code or any portion thereof, please include a
//   reference link back to http://www.bearnakedcode.com.
namespace AdjustableHeightTextbox
{
    /// <summary>
    /// A TextBox control that allows you to set the height of the TextBox.
    /// </summary>
    public partial class AdjHeightTextBox : TextBox
    {
        // Original height before Dock property set
        int ciPreDockHeight;
        // Original Distance to Bottom - used when set to AnchorStyles.Bottom
        int ciOrigDistanceToBottom;
        // If the textbox is set to multi-line, do the default value
        bool IsMultiLine = false;
        
        public AdjHeightTextBox()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Sets the height of a textbox by adjusting the size of the font
        /// </summary>
        /// <param name="TextBoxHeight">Height of the textbox</param>
        /// <param name="OriginalFont">Font used</param>
        /// <returns>Returns a font object with the correct size to adjust the TextBox size.</returns>
        private static Font GetFontForTextBoxHeight(int TextBoxHeight, Font OriginalFont)
        {
            // What is the target size of the text box?
            float desiredheight = (float)TextBoxHeight;

            // Set the font from the existing TextBox font.
            // We use the fnt = new Font(...) method so we can ensure that
            //  we're setting the GraphicsUnit to Pixels.  This avoids all
            //  the DPI conversions between point & pixel.
            Font fnt = new Font(OriginalFont.FontFamily,
                                OriginalFont.Size,
                                OriginalFont.Style,
                                GraphicsUnit.Pixel);

            // TextBoxes never size below 8 pixels. This consists of the
            // 4 pixels above & 3 below of whitespace, and 1 pixel line of
            // greeked text.
            if (desiredheight < 8)
                desiredheight = 8;

            // Determine the Em sizes of the font and font line spacing
            // These values are constant for each font at the given font style.
            // and screen DPI.
            float FontEmSize = fnt.FontFamily.GetEmHeight(fnt.Style);
            float FontLineSpacing = fnt.FontFamily.GetLineSpacing(fnt.Style);

            // emSize is the target font size.  TextBoxes have a total of
            // 7 pixels above and below the FontHeight of the font.
            float emSize = (desiredheight - 7) * FontEmSize / FontLineSpacing;

            // Create the font, with the proper size to change the TextBox Height to the desired size.
            fnt = new Font(fnt.FontFamily, emSize, fnt.Style, GraphicsUnit.Pixel);

            return fnt;
        }

        /// <summary>
        /// Determines if we should perform the default base.XXX action.
        /// </summary>
        /// <returns>
        /// True if the parent is null, the control is disposing
        /// or the Multi-Line property is true.
        /// </returns>
        private bool DoDefault()
        {
            return (Parent == null || Disposing || IsMultiLine);
        }

        /// <summary>
        /// Sets the height of the TextBox - the Size.Height property is ignored on TextBox controls
        /// </summary>
        [System.ComponentModel.Category("Layout")]
        [System.ComponentModel.Description("Set the TextBox.Height.")]
        public int Size_AdjustableHeight
        {
            get { return this.Height; }
            set
            {
                // If the parent does not exist, we're set to multi-line
                // or we are disposing, do default
                if (DoDefault())
                    return;
                if (value != this.Height)
                {
                    this.Height = value;
                    ciOrigDistanceToBottom = Parent.ClientSize.Height + this.Top - value;
                    this.Font = GetFontForTextBoxHeight(value, this.Font);
                }
            }
        }

        // If multi-line is set to true, set IsMultiline.  The control
        // will perform the default base.XXX actions.
        public override bool Multiline
        {
            get
            {
                return base.Multiline;
            }
            set
            {
                IsMultiLine = value;
                base.Multiline = value;
            }
        }

        // If the dock style changes to a height-adjusting value, get the original
        // size first
        public override DockStyle Dock
        {
            get
            {
                return base.Dock;
            }
            set
            {
                // If the parent does not exist, we're set to multi-line
                // or we are disposing, do default
                if (DoDefault())
                {
                    base.Dock = value;
                    return;
                }

                // if this docking change should affect the height
                if ((value & DockStyle.Left) == DockStyle.Left ||
                    (value & DockStyle.Right) == DockStyle.Right ||
                    (value & DockStyle.Fill) == DockStyle.Fill)
                {
                    // and if the base.dock is NOT ALREADY set to a height-adjusting
                    // DockStyle, then get the original height.
                    if ((base.Dock & DockStyle.Left) != DockStyle.Left &&
                        (base.Dock & DockStyle.Right) != DockStyle.Right &&
                        (base.Dock & DockStyle.Fill) != DockStyle.Fill)
                        ciPreDockHeight = Height;
                }
                base.Dock = value;
            }
        }

        // Intercept TextBox.OnDockChanged to adjust the height of textbox
        // back to its original pre-dock value, if necessary.
        protected override void OnDockChanged(EventArgs e)
        {
            // If the parent does not exist, we're set to multi-line
            // or we are disposing, do default
            if (DoDefault())
            {
                base.OnDockChanged(e);
                return;
            }

            // if this docking change is bottom or none, set the height back to 
            // the original pre-dock value.
            if ((this.Dock & DockStyle.Bottom) == DockStyle.Bottom ||
                (this.Dock & DockStyle.None) == DockStyle.None)
            {
                this.Font = GetFontForTextBoxHeight(ciPreDockHeight, this.Font);
            }
            base.OnDockChanged(e);
        }

        // Intercept OnParentChanged to set distance to bottom for Anchoring
        // and add an event subscription to Parent.ClientSizeChanged
        protected override void OnParentChanged(EventArgs e)
        {
            // If the parent does not exist, we're set to multi-line
            // or we are disposing, do default
            if (DoDefault())
            {
                base.OnDockChanged(e);
                return;
            }
            ciOrigDistanceToBottom = Parent.ClientSize.Height - this.Bottom;
            ciPreDockHeight = this.Height;
            Parent.ClientSizeChanged += new EventHandler(Parent_ClientSizeChanged);
            base.OnParentChanged(e);
        }

        // Event Handler for Parent.ClientSizeChanged
        // If the parent size changes, we may need to adjust the textbox size
        // if it is docked or anchored.
        void Parent_ClientSizeChanged(object sender, EventArgs e)
        {
            // If the parent does not exist, we're set to multi-line
            // or we are disposing, do default
            if (DoDefault())
            {
                base.OnDockChanged(e);
                return;
            }

            if ((this.Dock & DockStyle.Left) == DockStyle.Left ||
                (this.Dock & DockStyle.Right) == DockStyle.Right ||
                (this.Dock & DockStyle.Fill) == DockStyle.Fill ||
                (this.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)
                this.Font = GetFontForTextBoxHeight(Parent.ClientSize.Height, this.Font);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            // If the parent does not exist, we're set to multi-line
            // or we are disposing, do default
            if (DoDefault())
            {
                base.OnSizeChanged(e);
                return;
            }

            int height = this.Height;
            // Is the control docked or anchored to bottom?
            switch (this.Dock)
            {
                case DockStyle.Fill:
                case DockStyle.Left:
                case DockStyle.Right:
                    height = Parent.ClientSize.Height;
                    this.Font = GetFontForTextBoxHeight(height, this.Font);
                    break;
                // Not docked in a way that should modify height.
                default:
                    // Check for Anchoring that should change the height.
                    // If so, set the height based on the original distance to bottom.
                    if ((this.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)
                    {
                        height = Parent.ClientSize.Height - ciOrigDistanceToBottom;
                        this.Font = GetFontForTextBoxHeight(height, this.Font);
                    }
                    break;
            }

            base.OnSizeChanged(e);
        }
    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Systems Engineer ThomsonReuters Tax & Accounting
United States United States
I am a Senior System Administrator for a 400+ server ASP farm. With such a large farm and limited staff, our goal is to add as much automation as possible to the system. Most of my programming consists of intelligent slack: spending 2 hours to write a program that handles a reoccurring 10 minute manual job.

Comments and Discussions