Click here to Skip to main content
15,169,069 members
Articles / Desktop Programming / Windows Forms
Posted 12 Nov 2008


212 bookmarked

RichText Builder (StringBuilder for RTF)

Rate me:
Please Sign up or sign in to vote.
4.86/5 (102 votes)
12 Nov 2008CPOL4 min read
RichText Builder - use in place of StringBuilder to output RTF.


Manipulating Rich Text (RTF) - how to do it?

I expected it to be a relatively easy task. Surely, there was something out there that would allow RTF generation. I did not want to resort to HTML. I required tables, colour, font size, image insertion, and the ability to merge RTF documents preserving all the above formatting. I really needed something simple and fast. Say, as simple and easy as StringBuilder.

Rich Text is ubiquitous in Windows Forms applications, yet notoriously hard to manipulate programmatically. Display of Rich Text is based on the RTF specification (an archaic format dating way back to early Windows 3.0). Parsing Rich Text is beyond the scope of this article. If, however, you need to build up a simple rich text with font style, font, font size, font colour, back colour, tables, and insert images and merge RTF documents, then this little utility class (RTFBuilder) may help you.


Programmatic manipulation of RTF within a RichTextBox was my first attempt, and I had it working to a point. The crunch came when trying to create tables. Anyone who has worked with the a RichTextBox and RTF tables will know what I mean.

After searching all over the net - Nada, apart from commercial controls - I was prepared to pay a couple of hundred dollars for such a utility, if it existed.

TextControl [a very good commercial control] allows display, editing, and programmatic generation of RTF, but was out of my price range and requirements. I also didn't like the size of the redistributable(s), and the difficulties of distributing the control with a small ClickOnce application, for example. The required learning curve for programmatic generation of RTF using the TextControl API was not insignificant.

RtfBuilder was the fruition of many hours of learning RTF specification and tinkering. RtfBuilder is based on the StringBuilder class design.

The beauty of RtfBuilder is in the fact that it can be used interchangeably in place of StringBuilder. It will output RTF when ToString() is Called.

You can rapidly develop your code initially with StringBuilder, and convert to the usage of Rich Text by replacing the initialization code with that of an RtfBuilder.

The RTF specification is reasonably large, and this utility uses just a small part of the specification to get the job done. Because of its (and my) limited knowledge of the RTF specification, there are limitations when merging RTF documents. Generally, RTF code from RichTextBox controls can be merged but Rich Text pasted from MS Word may cause problems when merging.

There are ways around prickly specifications when you just want to perform a subset of functions to get the job done.

Using the code

Create a new RTFBuilder, and simply append text in a similar fashion to StringBuilder usage.

Add formatting calls where necessary, prior to appending text. The format resets to default after each append, unless enclosed within a using FormatLock(sb.FormatLock()) {sb.Append....}. RtfBuilder also allows AppendFormat("{0}", arg); and AppendLineFormat("{0}",arg); (something that StringBuilder should have!)

RTFBuilderbase sb = new RTFBuilder();
sb.AppendLine("AppendLine Basic Text");

sb.Append("append text1").Append("append text2").Append(
   "append text3").Append("append text4").AppendLine();





sb.FStyle(FontStyle.Bold | FontStyle.Italic | FontStyle.Strikeout | 

sb.ForeColor(KnownColor.Red).AppendLine("ForeColor Red");

sb.BackColor(KnownColor.Yellow).AppendLine("BackColor Yellow");
string rtf = sb.ToString();
this.richTextBox1.Rtf = rtf.

// Merging an RTF Document is sublimely simple

//Inserting an Image - again very simple

I have included a very simple application demonstrating the usage:

Image 1

Also included is a GDFBuilder class which can be used interchangeably with the RtfBuilder (base) in code, and will generate images that can be displayed in a paging image control (included).

I have used the GDFBuilder to create RTF popup tooltips and RTF labels by painting the images from the GDFPages exposed by the GDFPageManager. You will need to hunt around in the code to find this feature. I have not included a demo - if you are interested, post a comment.

Points of interest

It would be very easy to add an HtmlBuilder using the existing RtfBuilder framework.

There is extensive usage of IDisposable within the code that inserts RTF format commands. This allows RTF codes such as that for bold (/b) to be prepended before a string insert, and that for unbold (/b0) to be appended after the string insert.

Table creation is non-intuitive. You need to create the row and cell definitions and then enumerate over the cells. The EnumerateCells functions return an IEnumerable<RTFBuilderbase> which represents the underlying RTFBuilderbase, wrapped with a class that emits the correct RTF row and cell codes as you enumerate the cells.

private void AddRow1(RTFBuilderbase sb, params string[] cellContents)

  Padding p = new Padding { All = 50 };//Padding is ignored
  //Create row definition
  RTFRowDefinition rd = new RTFRowDefinition(88, RTFAlignment.TopLeft, 
                        RTFBorderSide.Default, 15, SystemColors.WindowText, p);
  //Create Cell Definitions
  RTFCellDefinition[] cds = new RTFCellDefinition[cellContents.Length];
  for (int i = 0; i < cellContents.Length; i++)
   cds[i] = new RTFCellDefinition(88 / cellContents.Length, RTFAlignment.TopLeft, 
            RTFBorderSide.Default, 15, Color.Blue, Padding.Empty);

  int pos = 0;
  // Enumerate the cells
  // Each cell exposes an RtfBuilderbase so you can insert images,
  // format rtf i.e. all RtfBuilder functions , within the cell
  foreach (RTFBuilderbase item in sb.EnumerateCells(rd, cds))
   item.ForeColor(KnownColor.Blue).FStyle(FontStyle.Bold | FontStyle.Underline);


  • 12 Nov 2008 - Version 1
  • I have used this code extensively for the last few months in an application, and it seems stable, but the GDFBuilder still needs work. Also, padding and borders for table/row/cells is incomplete and nonfunctional.


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


About the Author

Australia Australia
Interested in financial math and programming theory in general. Working on medical applications in spare time. Happy to get feedback.

Comments and Discussions

AnswerRe: Alignment? Pin
Tomm6un5-Jun-13 11:18
MemberTomm6un5-Jun-13 11:18 
AnswerRe: Alignment? Pin
Fred J. Cimo Jr.5-Sep-20 15:56
MemberFred J. Cimo Jr.5-Sep-20 15:56 
QuestionHow can I insert a string or image to rtf somewhere ? Pin
sjs97@163.com12-Apr-13 1:02
Membersjs97@163.com12-Apr-13 1:02 
AnswerRe: How can I insert a string or image to rtf somewhere ? Pin
seeblunt12-Apr-13 6:07
Memberseeblunt12-Apr-13 6:07 
GeneralRe: How can I insert a string or image to rtf somewhere ? Pin
sjs97@163.com14-Apr-13 5:09
Membersjs97@163.com14-Apr-13 5:09 
Questionpublic void Clear(){} Pin
calebboyd15-Jan-13 18:51
Membercalebboyd15-Jan-13 18:51 
BugAbout the RTFAlignment Pin
ReynoldCQ13-Sep-12 17:50
MemberReynoldCQ13-Sep-12 17:50 
GeneralRe: About the RTFAlignment Pin
seeblunt13-Sep-12 18:07
Memberseeblunt13-Sep-12 18:07 
The RichText Control exposed by dotnet does not handle table text well. Reflowing lines and alignment are handled poorly.
You can try using this Richtext box which uses a different control
internal class RichTextBox5 : RichTextBox
       private static IntPtr moduleHandle;
       //private static int richEditMajorVersion=4;

       [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
       private static extern IntPtr LoadLibrary(string libname);
       //[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
       //private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);

       protected override CreateParams CreateParams

               CreateParams cp = null;
               if (!DesignMode)
                   OperatingSystem os = Environment.OSVersion;

                   if ((os.Version.Major <= 4) || ((os.Version.Major == 5) && (os.Version.Minor == 0)))
                       cp = base.CreateParams;
                           cp = GetCreateParams();

                           cp = base.CreateParams;
                   return cp;
               return base.CreateParams;

       private  CreateParams GetCreateParams()
           if (moduleHandle == IntPtr.Zero)

               moduleHandle = LoadLibrary("msftedit.dll");
               int error = Marshal.GetLastWin32Error();
               if (((long)moduleHandle) < 0x20L)
                   throw new Win32Exception(error, "LoadDLLError msftedit.dll");

           CreateParams createParams = base.CreateParams;
           createParams.ClassName = Marshal.SystemDefaultCharSize == 1 ? "RICHEDIT50A" : "RICHEDIT50W";
           if (this.Multiline)
               if (((this.ScrollBars & RichTextBoxScrollBars.Horizontal) != RichTextBoxScrollBars.None) && !base.WordWrap)
                   createParams.Style |= 0x100000;
                   if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None)
                       createParams.Style |= 0x2000;
               if ((this.ScrollBars & RichTextBoxScrollBars.Vertical) != RichTextBoxScrollBars.None)
                   createParams.Style |= 0x200000;
                   if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None)
                       createParams.Style |= 0x2000;
           if ((BorderStyle.FixedSingle == base.BorderStyle) && ((createParams.Style & 0x800000) != 0))
               createParams.Style &= -8388609;
               createParams.ExStyle |= 0x200;
           return createParams;

GeneralRe: About the RTFAlignment Pin
ReynoldCQ13-Sep-12 22:47
MemberReynoldCQ13-Sep-12 22:47 
GeneralMy vote of 5 Pin
lebo815-Aug-12 13:52
Memberlebo815-Aug-12 13:52 
QuestionDefinitely thank you! Pin
MorpheusMTL27-Jun-12 10:47
MemberMorpheusMTL27-Jun-12 10:47 
QuestionThis is just what I was looking for. Many thanks. Pin
Chelsea FC17-Dec-11 12:15
MemberChelsea FC17-Dec-11 12:15 
QuestionMy vote of 5 Pin
Filip D'haene13-Sep-11 1:59
MemberFilip D'haene13-Sep-11 1:59 
GeneralMy vote of 5 Pin
orighost12-Aug-11 4:51
Memberorighost12-Aug-11 4:51 
GeneralProblem escaping { and } Pin
RudolfHenning12-Apr-11 4:10
MemberRudolfHenning12-Apr-11 4:10 
GeneralRe: Problem escaping { and } [modified] Pin
seeblunt14-Apr-11 5:59
Memberseeblunt14-Apr-11 5:59 
GeneralRe: Problem escaping { and } Pin
RudolfHenning14-Apr-11 7:08
MemberRudolfHenning14-Apr-11 7:08 
QuestionIs there a way to use dynamically changed fonts in RTFlib ? Pin
rezbekt6-Jan-11 17:33
Memberrezbekt6-Jan-11 17:33 
AnswerRe: Is there a way to use dynamically changed fonts in RTFlib ? Pin
seeblunt7-Jan-11 1:28
Memberseeblunt7-Jan-11 1:28 
QuestionIs there a way to use dynamically changed fonts in RTFlib ? Pin
rezbekt5-Jan-11 10:02
Memberrezbekt5-Jan-11 10:02 
AnswerRe: Is there a way to use dynamically changed fonts in RTFlib ? Pin
seeblunt5-Jan-11 15:35
Memberseeblunt5-Jan-11 15:35 
GeneralRe: Is there a way to use dynamically changed fonts in RTFlib ? Pin
rezbekt6-Jan-11 14:57
Memberrezbekt6-Jan-11 14:57 
GeneralMy vote of 4 Pin
Slacker00723-Dec-10 0:42
professionalSlacker00723-Dec-10 0:42 
GeneralThanks so much Pin
davian7229-Sep-10 4:22
Memberdavian7229-Sep-10 4:22 
GeneralBug with fractional text Pin
jeffb425-Sep-10 15:55
Memberjeffb425-Sep-10 15:55 

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.