Click here to Skip to main content
15,912,457 members
Articles / Multimedia / GDI+
Article

RichTextBoxExtended

Rate me:
Please Sign up or sign in to vote.
4.85/5 (81 votes)
21 Jun 20064 min read 464.5K   11.6K   217   172
A RichTextBox with a richtext toolbar.

RichTextBoxExtended ScreenShot

Introduction

Hello again, my friends. Today's control is a very simple yet useful control. It is a custom control that contains both a RichTextBox and a Toolbar. Now you might ask: "Why is that so important and useful?" It's because I have taken the liberty to do some coding for you. The toolbar not only looks pretty but it's functional too. It contains some of the everyday, plain, and simple things you want your users to be able to do when they input text.

Background

[Cheesy flashback music and graphics.] It all started when I was trying to remember how to insert a rich text "stamp" into a RichTextBox. Along the road to remembering, I thought to myself "Self, wouldn't it be easier not to have to remember this stuff every 6 months?" My answer was a big yes. It would be easier if I just built a control to use every time I needed users to input text. Then thinking of all the wonderful and helpful people on The Code Project, I decided to distribute my control so that everyone can learn how to do this stuff and also so they will have a pre-built control for use whenever they want.

Using the control

There are two ways you can use this control. You can either add the RichTextBoxExtended.cs file to your project and use the control by setting it up in code, or you can add the control to your toolbar and drag it on to your Form. One other thing, if you add the .cs file to your project, you will also have to add an ImageList to your project that contains all the images for the Toolbar. I prefer (and suggest) the latter method because I get to see the control on the form and I don't have to create the ImageList on every form I want to use this control on.

There are several properties that will help you use this control, and they are listed below:

  • AcceptsTab
  • AutoWordSelection
  • ReadOnly
  • ShowBold
  • ShowCenterJustify
  • ShowColors
  • ShowCopy
  • ShowCut
  • ShowFont
  • ShowFontSize
  • ShowItalic
  • ShowLeftJustify
  • ShowOpen
  • ShowPaste
  • ShowRedo
  • ShowRightJustify
  • ShowSave
  • ShowStamp
  • ShowStrikeout
  • ShowUnderline
  • ShowUndo
  • StampColor
  • StampAction
  • Toolbar - only use at runtime, changes that are made at design time will not persist.
  • RichTextBox - only use at runtime, changes that are made at design time will not persist.

Out of all of these, most of them are simply turning features on and off. The only really special ones are StampColor, StampAction, Toolbar, and RichTextBox.

  • StampColor is what it sounds like. It is the color the text will be in when a stamp is added to the RichTextBox.
  • StampAction can be one of three values: EditedBy, DateTime, or Custom.
  • EditBy is a string that reads "Edited by " + CurrentPrincipal.Identity.Name + " (theUserName) on " + DateTime.Now.ToLongDateString().
  • DateTime: DateTime.Now.ToLongDateString().
  • Custom: For Custom, you must handle the stamp event of this control.
C#
private void richTextBoxExtended1_Stamp(object sender, System.EventArgs e)
{
    //holds our stamp text
    StringBuilder stamp = new StringBuilder("");
    if(richTextBoxExtended1.RichTextBox.Text.Length > 0)
      stamp.Append("\r\n\r\n"); //add two lines for space
    stamp.Append("Custom stamp goes here!\r\n");

    //unselect everything basicly
    richTextBoxExtended1.RichTextBox.SelectionLength = 0;
    richTextBoxExtended1.RichTextBox.SelectionStart =
       richTextBoxExtended1.RichTextBox.Text.Length;
       //start new selection at the end of the text

    richTextBoxExtended1.RichTextBox.SelectionColor
      = richTextBoxExtended1.StampColor;
      //make the selection blue
    richTextBoxExtended1.RichTextBox.SelectionFont =
      new Font(richTextBoxExtended1.RichTextBox.SelectionFont,
      FontStyle.Bold); //set the selection font and style
    richTextBoxExtended1.RichTextBox.AppendText(stamp.ToString());
    //add the stamp to the richtextbox

    richTextBoxExtended1.RichTextBox.Focus();
    //set focus back on the richtextbox
}

Points of Interest

The biggest point of interest after all these months now is the amount of feedback, interest, and work one little control can bring to your life. I haven't been able to maintain this code like I wanted but thanks to all that have helped and made suggestions along the way. Along with this updated article comes news of RichTextBoxExtended for Framework 2.0. So if you want all these features in VS 2005 then keep watching. Anyone wanting to help, just email me.

OK, so what did I learn from this control and this experience? I learned about Exclusive-OR. This is a really handy operation that saved me 100 or so lines of code in this control. In the code below, the OR is the "^". The best way I can explain it is, it takes two values like 00000001 and 00000010 and compares them. In the example below, it checks the style and if the style = 00000001, it will change it to 00000000, however if it is 00000000, then it will change it to 00000001. That isn't the best explanation of this operation, so below the code are some links for you.

C#
rtb1.SelectionFont = new Font(rtb1.SelectionFont,
              rtb1.SelectionFont.Style ^ FontStyle.Bold);

History

  • 1.0 - Initial release - 1/31/2004.
  • 1.1 - 4/18/2005.
    • Font Selector added.
    • Font Size Selector added.
    • Fixed error that caused the control to crash when two or more font types were selected.
    • Cleaned up the code.
  • 1.2 - 12/12/2005
    • Fixed multiple font selection bug. You can now add font styles (e.g. Bold and Color) when selecting two different fonts at the same time.
    • Added a selection change event named SelChanged.
    • Added cut, copy and paste buttons.
    • The control now uses the ToolBarButton.Tag property instead of the ToolBarButton.ToolTip property for button presses. Now you can have your tooltips be whatever you like.
    • Added DetectUrls property. You can have HTTP links in your RichTextBox and click them to open the system default browser.
    • Added a ReadOnly property.
    • Added AcceptsTabs property.
    • Added AutoWordSelection property.
    • Added keyboard handler for Ctrl+B, Ctrl+I, Ctrl+S, Ctrl+U, Ctrl+-.
    • The download now comes with all the images. I also included a print image.
    • Cleaned up the code.

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
Web Developer
United States United States
Richard is a contract developer that currently lives in Arkansas. He has spent most of his career working in healthcare related companies. On his first job he was programming asp using VBScript and his boss walked in and told the whole group to get in their cars and drive to Barnes and Nobles. Once there he let everyone buy a few books about .NET and then he dropped the bomb, he said we would no longer write asp code. Starting Monday we were to be .NET developers.

Five years later Richard is a competent and self motivated .NET developer that can tackle most any problem. He has recently started his own business BellaDev which is proving to be a fun and challenging opportunity.

Comments and Discussions

 
GeneralNow supports form persistance and data binding Pin
Declan Brennan14-Feb-06 4:26
Declan Brennan14-Feb-06 4:26 
GeneralDatabase binding. Pin
Almatrodi12-Feb-06 1:52
Almatrodi12-Feb-06 1:52 
GeneralRe: Database binding. Pin
Declan Brennan14-Feb-06 4:38
Declan Brennan14-Feb-06 4:38 
GeneralUsing in .NET 2.0 Project Pin
James.H.Byrd2-Feb-06 10:39
James.H.Byrd2-Feb-06 10:39 
Questionrtf and page breaks? Pin
Cristian Pellegrini28-Nov-05 19:40
Cristian Pellegrini28-Nov-05 19:40 
GeneralKeyboard shortcuts [modified] Pin
Marek Grzenkowicz25-Nov-05 23:48
Marek Grzenkowicz25-Nov-05 23:48 
GeneralRe: Keyboard shortcuts - an update [modified] Pin
Marek Grzenkowicz5-Dec-05 10:41
Marek Grzenkowicz5-Dec-05 10:41 
GeneralRe: Keyboard shortcuts - an update Pin
cbumstead14-Jun-06 11:23
cbumstead14-Jun-06 11:23 
I'm not sure if the source code for the RichTextBoxExtended control was modified, because when I tried to add the above Keyboard Shortcut code it didn't work. This was for two reasons:

1. Odviously, the handlers need to be wired up to the events. This was simple.
2. Not so odvious was that the tb1_ButtonClick handler relied on the button state (pushed or not) for the selected text. The shortcut code is calling this handler but not simulating the pressing of the button first so nothing ever happends. The solution is to add this line to the rtb1_KeyDown method before calling tb1_ButtonClick(null, args);

<br />
args.Button.Pushed = !args.Button.Pushed;<br />


Here's the full code:

#region Change font style
/// <summary>
///     Change the richtextbox style for the current selection
/// </summary>
public void ChangeFontStyle(FontStyle style, bool add)
{
    //This method should handle cases that occur when multiple fonts/styles are selected
    // Parameters:-
    //  style - eg FontStyle.Bold
    //  add - IF true then add else remove

    // throw error if style isn't: bold, italic, strikeout or underline
    if (   style != FontStyle.Bold
        && style != FontStyle.Italic
        && style != FontStyle.Strikeout
        && style != FontStyle.Underline)
            throw new  System.InvalidProgramException("Invalid style parameter to ChangeFontStyle");

    int rtb1start = rtb1.SelectionStart;
    int len = rtb1.SelectionLength;
    int rtbTempStart = 0;

    //if len <= 1 and there is a selection font then just handle and return
    if(len <= 1 && rtb1.SelectionFont != null)
    {
        //add or remove style
        if (add)
            rtb1.SelectionFont = new Font(rtb1.SelectionFont, rtb1.SelectionFont.Style | style);
        else
            rtb1.SelectionFont = new Font(rtb1.SelectionFont, rtb1.SelectionFont.Style & ~style);

        return;
    }

    // Step through the selected text one char at a time
    rtbTemp.Rtf = rtb1.SelectedRtf;
    for(int i = 0; i < len; ++i)
    {
        rtbTemp.Select(rtbTempStart + i, 1);

        //add or remove style
        if (add)
            rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style | style);
        else
            rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style & ~style);
    }

    // Replace & reselect
    rtbTemp.Select(rtbTempStart,len);
    rtb1.SelectedRtf = rtbTemp.SelectedRtf;
    rtb1.Select(rtb1start,len);
    return;
}
#endregion

#region Change font size
/// <summary>
///     Change the richtextbox font size for the current selection
/// </summary>
public void ChangeFontSize(float fontSize)
{
    //This method should handle cases that occur when multiple fonts/styles are selected
    // Parameters:-
    // fontSize - the fontsize to be applied, eg 33.5

    if (fontSize <= 0.0)
        throw new System.InvalidProgramException("Invalid font size parameter to ChangeFontSize");

    int rtb1start = rtb1.SelectionStart;
    int len = rtb1.SelectionLength;
    int rtbTempStart = 0;

    // If len <= 1 and there is a selection font, amend and return
    if (len <= 1 && rtb1.SelectionFont != null)
    {
        rtb1.SelectionFont =
            new Font(rtb1.SelectionFont.FontFamily, fontSize, rtb1.SelectionFont.Style);
        return;
    }

    // Step through the selected text one char at a time
    rtbTemp.Rtf = rtb1.SelectedRtf;
    for(int i = 0; i < len; ++i)
    {
        rtbTemp.Select(rtbTempStart + i, 1);
        rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont.FontFamily, fontSize, rtbTemp.SelectionFont.Style);
    }

    // Replace & reselect
    rtbTemp.Select(rtbTempStart,len);
    rtb1.SelectedRtf = rtbTemp.SelectedRtf;
    rtb1.Select(rtb1start,len);
    return;
}
#endregion

#region Change font color
/// <summary>
///     Change the richtextbox font color for the current selection
/// </summary>
public void ChangeFontColor(Color newColor)
{
    //This method should handle cases that occur when multiple fonts/styles are selected
    // Parameters:-
    //  newColor - eg Color.Red

    int rtb1start = rtb1.SelectionStart;
    int len = rtb1.SelectionLength;
    int rtbTempStart = 0;

    //if len <= 1 and there is a selection font then just handle and return
    if(len <= 1 && rtb1.SelectionFont != null)
    {
        rtb1.SelectionColor = newColor;
        return;
    }

    // Step through the selected text one char at a time
    rtbTemp.Rtf = rtb1.SelectedRtf;
    for(int i = 0; i < len; ++i)
    {
        rtbTemp.Select(rtbTempStart + i, 1);

        //change color
        rtbTemp.SelectionColor = newColor;
    }

    // Replace & reselect
    rtbTemp.Select(rtbTempStart,len);
    rtb1.SelectedRtf = rtbTemp.SelectedRtf;
    rtb1.Select(rtb1start,len);
    return;
}
#endregion

#region Get Font Details
/// <summary>
///     Returns a Font with:
///     1) The font applying to the entire selection, if none is the default font.
///     2) The font size applying to the entire selection, if none is the size of the default font.
///     3) A style containing the attributes that are common to the entire selection, default regular.
/// </summary>
///
public Font GetFontDetails()
{
    //This method should handle cases that occur when multiple fonts/styles are selected

    int rtb1start = rtb1.SelectionStart;
    int len = rtb1.SelectionLength;
    int rtbTempStart = 0;

    if (len <= 1)
    {
        // Return the selection or default font
        if (rtb1.SelectionFont != null)
            return rtb1.SelectionFont;
        else
            return rtb1.Font;
    }

    // Step through the selected text one char at a time
    // after setting defaults from first char
    rtbTemp.Rtf = rtb1.SelectedRtf;

    //Turn everything on so we can turn it off one by one
    FontStyle replystyle =
        FontStyle.Bold | FontStyle.Italic | FontStyle.Strikeout | FontStyle.Underline;

    // Set reply font, size and style to that of first char in selection.
    rtbTemp.Select(rtbTempStart, 1);
    string replyfont = rtbTemp.SelectionFont.Name;
    float replyfontsize = rtbTemp.SelectionFont.Size;
    replystyle = replystyle & rtbTemp.SelectionFont.Style;

    // Search the rest of the selection
    for(int i = 1; i < len; ++i)
    {
        rtbTemp.Select(rtbTempStart + i, 1);

        // Check reply for different style
        replystyle = replystyle & rtbTemp.SelectionFont.Style;

        // Check font
        if (replyfont != rtbTemp.SelectionFont.FontFamily.Name)
            replyfont = "";

        // Check font size
        if (replyfontsize != rtbTemp.SelectionFont.Size)
            replyfontsize = (float)0.0;
    }

    // Now set font and size if more than one font or font size was selected
    if (replyfont == "")
        replyfont = rtbTemp.Font.FontFamily.Name;

    if (replyfontsize == 0.0)
        replyfontsize = rtbTemp.Font.Size;

    // generate reply font
    Font reply
        = new Font(replyfont, replyfontsize, replystyle);

    return reply;
}
#endregion

#region Keyboard shortcuts - Added by chopeen
private void rtb1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
  if (e.Modifiers == Keys.Control)
  {
    ToolBarButtonClickEventArgs args = null;

    switch (e.KeyCode)
    {
      case Keys.B:
        args = new ToolBarButtonClickEventArgs(this.tbbBold);
        break;
      case Keys.I:
        args = new ToolBarButtonClickEventArgs(this.tbbItalic);
        break;
      case Keys.S:
        args = new ToolBarButtonClickEventArgs(this.tbbStamp);
        break;
      case Keys.U:
        args = new ToolBarButtonClickEventArgs(this.tbbUnderline);
        break;
      /* this is a default shortcut; no need to define it again
      case Keys.Z:
        args = new ToolBarButtonClickEventArgs(this.tbbUndo);
        break; */
      case Keys.OemMinus:
        args = new ToolBarButtonClickEventArgs(this.tbbStrikeout);
        break;
    }

    if (args != null)
    {
        args.Button.Pushed = !args.Button.Pushed;
        tb1_ButtonClick(null, args);
    }
  }
}

private void rtb1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
  switch ((int) e.KeyChar)
  {   // Ctrl+I inserts a tab (char HT) into a textbox
    case 9:
        e.Handled = true;
      break;
  }
}
#endregion


AND add this to InitializeComponent()

<br />
this.rtb1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.rtb1_KeyDown);<br />
this.rtb1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.rtb1_KeyPress);<br />

GeneralRe: Keyboard shortcuts - an update Pin
cbumstead14-Jun-06 11:26
cbumstead14-Jun-06 11:26 
GeneralRe: Keyboard shortcuts - an update Pin
Richard Parsons15-Jun-06 11:52
Richard Parsons15-Jun-06 11:52 
GeneralRe: Keyboard shortcuts - an update Pin
cbumstead15-Jun-06 18:14
cbumstead15-Jun-06 18:14 
AnswerRe: Keyboard shortcuts - an update Pin
Richard Parsons20-Jun-06 4:26
Richard Parsons20-Jun-06 4:26 
GeneralRe: Keyboard shortcuts - an update Pin
Richard Parsons21-Jun-06 11:50
Richard Parsons21-Jun-06 11:50 
GeneralRe: Keyboard shortcuts - an update Pin
cbumstead21-Jun-06 18:13
cbumstead21-Jun-06 18:13 
GeneralRe: Keyboard shortcuts Pin
BillWoodruff26-Dec-05 8:58
professionalBillWoodruff26-Dec-05 8:58 
GeneralRe: Keyboard shortcuts [modified] Pin
Marek Grzenkowicz28-Dec-05 3:36
Marek Grzenkowicz28-Dec-05 3:36 
AnswerRe: Keyboard shortcuts Pin
Richard Parsons28-Dec-05 9:43
Richard Parsons28-Dec-05 9:43 
GeneralRe: Keyboard shortcuts Pin
Steve Barnett22-Feb-06 2:24
Steve Barnett22-Feb-06 2:24 
Question.Rtf property does not work? Pin
flo122719-Oct-05 3:14
flo122719-Oct-05 3:14 
AnswerRe: .Rtf property does not work? Pin
torial19-Oct-05 12:05
torial19-Oct-05 12:05 
AnswerRe: .Rtf property does not work? Pin
Richard Parsons20-Oct-05 15:13
Richard Parsons20-Oct-05 15:13 
GeneralRe: .Rtf property does not work? Pin
Declan Brennan14-Feb-06 4:41
Declan Brennan14-Feb-06 4:41 
QuestionA couple of problems Pin
Nickrus13-Oct-05 10:41
Nickrus13-Oct-05 10:41 
QuestionProblem with instance Pin
H. Roessner16-Sep-05 11:32
H. Roessner16-Sep-05 11:32 
AnswerRe: Problem with instance Pin
Richard Parsons4-Oct-05 15:09
Richard Parsons4-Oct-05 15:09 

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.