Click here to Skip to main content
15,891,316 members
Articles / Programming Languages / C#
Article

A Padded Text Box Control

Rate me:
Please Sign up or sign in to vote.
2.33/5 (3 votes)
28 Mar 20073 min read 76.7K   990   13   3
A user control which adds a new property to a rich text box control

Introduction

One property that the text box controls are lacking is the Padding property which I have added with this user control. This allows you to place a border around the actual text which can improve the look of the text box. The border color may be a different color from the text background in which case it acts to "frame" the text, as in the example above, or it can be the same color in which case it acts as a margin.

Background

Creating this effect is relatively easy and MSDN provides some examples of how to do this using a text box and a panel. However, I would rather create a control with this property and then be able to reuse it subsequently without having to reinvent the wheel each time. After all, isn't that what user controls are for? In this case I have placed a rich text box on a user control surface which acts as the "panel" (as if you were to do it the MSDN way).

The user control code

C#
public partial class PTextBox : UserControl
{
/// <summary>
/// PTextBox is a simple user control which provides the missing "Padding"
/// property to a rich text box.  This allows the user to define a border
/// around the text.  This border can be the same color as the text box
/// in which case it is simply an inner padding or it can be a true border
/// of a different color.
/// <remarks>
/// The two properties of import are the padding size and the background
/// color of the control which acts as the border color for the text box.
/// The rich text box itself is exposed via the "rtb" control which is
/// public.
/// </remarks>
/// </summary>
    public PTextBox()
    {
        InitializeComponent();
    }

    /// <summary>
    /// This property allows the user to set the background color
    /// of the rich text box at design time.
    /// </summary>
    [
        Browsable(true),
        CategoryAttribute("Appearance"),
        Description("The background color of the rich text box.")
    ]

    public Color TextBackColor
    {
        get
        {
            return rtb.BackColor;
        }
        set
        {
            rtb.BackColor = value;
        }
    }

    /// <summary>
    /// This property allows the user to set the foreground color
    /// of the rich text box at design time.
    /// </summary>
    [
        Browsable(true),
        CategoryAttribute("Appearance"),
        Description("The foreground color of the rich text box.")
    ]

    public Color TextForeColor
    {
        get
        {
        return rtb.ForeColor;
        }
        set
        {
        rtb.ForeColor = value;
        }
    }

    /// <summary>
    /// This property allows the user to set the text property
    /// of the textbox directly without having to use the "rtb" property.
    /// </summary>
    [
        Browsable(true),
        CategoryAttribute("Data"),
        Description("The text of the rich text box.")
    ]

    public override string Text
    {
        get
        {
        return rtb.Text;
        }
        set
        {
        rtb.Text = value;
        }
    }

    /// <summary>
    /// The ToString() value of the rich text box.
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return rtb.ToString();
    }
}

Using the code

First compile the control and put the resulting dll in the folder of your choice, preferably one containing your reusable assemblies.

Open the toolbox. Right click and select "Choose items". In the "Choose Toolbox Items" dialog box, browse for PaddedTextBox.dll and select it for your project. Now you can treat this control almost as if it were the built-in rich text box with a few additional properties. In the properties window, I have exposed the Text property of the rich text box as well as added the TextForeColor and TextBackColor properties. The actual ForeColor and BackColor properties now apply to the user control, i.e., the border colors although, in this context, the ForeColor is meaningless. I have also made the rich text box named rtb, public, so programmatically you have full control over it if you need to access or change any other properties or trap any events.

The demo code below shows how to use the control. To simplify things I have created a separate reference to the rich text box so I don't have to keep referring to it via ptb.rtb. In this case ptb.TextBackColor and rtb.BackColor refer to the same property.

C#
using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Test
{
    public partial class Form1 : Form
    {
        private RichTextBox rtb;
        private byte clickType = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Use "rtb" to access the text box within the user control:
            rtb = ptb.rtb;
            rtb.Font = new Font("Tahoma", 12, FontStyle.Bold);
            // Note that we could also use rtb.Text here since they are essentially
            // the same:
            ptb.Text = "Click to change the text box background color.\r\n\r\n" +
                       "Double click to change the border color.\r\n\r\n" +
                       "Use the horizontal slider below to change the border size.\r\n\r\n" +
                       "Padding = ";
            // Set up traps for the text box events that you want to handle
            rtb.Click += new System.EventHandler(this.rtb_Click);
            rtb.DoubleClick += new System.EventHandler(this.rtb_DoubleClick);
            rtb.KeyDown += new System.Windows.Forms.KeyEventHandler(this.rtb_KeyDown);
            szBorder.Value = ptb.Padding.All;
            SetPadding();
            timer1.Interval = 500;
            timer1.Enabled = true;
        }

        /// <summary>
        /// Click to change the text box background color
        /// </summary>
        private void rtb_Click(object sender, EventArgs e)
        {
            clickType = 1;
            rtb.SelectionLength = 0;  // Prevent the click from causing a selection
        }

        /// <summary>
        /// Double click to change the border color
        /// </summary>
        private void rtb_DoubleClick(object sender, EventArgs e)
        {
            clickType = 2;
            rtb.SelectionLength = 0;  // Prevent the click from causing a selection
        }

        /// <summary>
        /// We use the timer to allow a doubleclick to be handled without first
        /// generating a single click event.
        /// </summary>
        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            if (clickType == 1)
            {
                DialogResult dr = this.colorDialog1.ShowDialog();
                if (dr == DialogResult.OK) ptb.TextBackColor = this.colorDialog1.Color;
            }
            else if (clickType == 2)
            {
                DialogResult dr = this.colorDialog1.ShowDialog();
                if (dr == DialogResult.OK) ptb.BackColor = this.colorDialog1.Color;
            }
            clickType = 0;
            timer1.Enabled = true;
        }

        /// <summary>
        /// You can trap key presses here.  This text box should be read-only
        /// so we don't allow any keystrokes in it.
        /// </summary>
        private void rtb_KeyDown(object sender, KeyEventArgs e)
        {
            e.SuppressKeyPress = true;
            e.Handled = true;   // This isn't required
        }

        private void szBorder_Scroll(object sender, ScrollEventArgs e)
        {
            SetPadding();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            SetPadding();
        }

        /// <summary>
        /// The scroll bar returns values between 0 and 100 inclusive.  Use that value
        /// as a percentage of half the smallest of the height and width to determine
        /// the border padding.  Note that the padding is uniform and does NOT
        /// reflect any difference between the height and width.
        /// </summary>
        private void SetPadding()
        {
            ptb.Padding = new Padding(Convert.ToInt32(szBorder.Value * .005 *
                (this.Width > this.Height ? this.Height : this.Width)));
            int i = rtb.Text.IndexOf("Padding =");
            rtb.Text = rtb.Text.Substring(0, i) + "Padding = " + ptb.Padding.All.ToString();
        }
    }
}

Points of Interest

Here's a little puzzle for you. I'm not sure that there is an easy solution for it that doesn't use reflection but I'd love to hear if there is one. Consider the BackColor property of the user control. Ideally I would like that and the ForeColor property to set the eponymous properties of the rich text box, not the user control panel. Then you could add a BorderColor property to set the background color of the control itself. The problem is that when you implement BorderColor, it must make a reference to the BackColor property but that has already been redefined to set the text box background color and, therefore, won't set the background that you want it to.

History

  • Release 1.0.0 – 07/26/2007

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


Written By
Software Developer (Senior) Takamomto, LLC
United States United States
I have been doing database related programming in the financial services industry for over 20 years on various platforms. I used to be a UNIX Sybase DBA but now prefer programming in the .NET environment using C# and SQL Server.

Comments and Discussions

 
QuestionMissing image? Pin
Ravi Bhavnani29-Mar-07 2:03
professionalRavi Bhavnani29-Mar-07 2:03 
GeneralBetter solution Pin
Georgi Atanasov28-Mar-07 23:15
Georgi Atanasov28-Mar-07 23:15 
Hi,

Much better solution for providing custom border and/or padding is to override the non-client handling of the control - the WM_NCCALCSIZE and WM_NCPAINT notifications, received via the WndProc. Using this approach you will not have the additional overhead of creating another wrapper control and the user will deal directly with the RichTextBox, not the wrapper.

Thanks,
Georgi

GeneralAnswer... Pin
partymonkey28-Mar-07 9:22
partymonkey28-Mar-07 9:22 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.