A Padded Text Box Control






2.33/5 (3 votes)
Mar 28, 2007
3 min read

77615

995
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
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.
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