Click here to Skip to main content
Click here to Skip to main content

A RichTextBox that can Bind to the RTF Property

By , 24 Jun 2010
 

Introduction

This control allows the user to quickly and easily databind an object to the Rtf property of a RichTextBox control.

Background

At work, I lead a team that has the task of converting our Microsoft Access 2003 application into a .NET app with a SQL 2005 backend database. Our program uses RTF formatted strings in too many places to count... Invoices, time cards, notes, appointments, document notes, project tasks, etc.

In Microsoft Access, we used a 3rd party ActiveX library called Total Access Memo, which was amazing for what we wanted to do. But in .NET, Microsoft was nice enough to give us the RichTextBox control. The only problem was the fact that they did not give us the ability to easily bind data to the Rtf property of the control!

So after using a completely hacked, round-a-bout method of binding the data, I asked myself 'What is the point of a RichTextBox that cannot bind to the rich text?' This question pestered me enough to where I had to fix it.

Using the Code

This control can be utilized just like the default RichTextBox. The only difference is that you now have an additional property called Rtf that is available under the '(Databindings)' category in the designer's PropertyGrid.

The dbRTBox class inherits System.Windows.Forms.RichTextBox class, and hides the Rtf property with a new one.

The code is surprisingly simple:

C#

using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace DataboundRTB
{
    [ClassInterface(ClassInterfaceType.AutoDispatch), DefaultBindingProperty("Rtf"), 
	Description("DescriptionRichTextBox"), ComVisible(true), 
	Docking(DockingBehavior.Ask), 
	Designer("System.Windows.Forms.Design.RichTextBoxDesigner, 
	System.Design, Version=4.0.0.0, Culture=neutral, 
	PublicKeyToken=b03f5f7f11d50a3a")]
    class dbRTBox : System.Windows.Forms.RichTextBox
    {
        [Bindable(true), RefreshProperties(RefreshProperties.All), 
	SettingsBindable(true), DefaultValue(""), Category("Appearance")]
        new public string Rtf
        {
            get
            {
                return base.Rtf;
            }
            set
            {
                base.Rtf = value;
            }
        }
    }
} 

VB

Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

<ClassInterface(ClassInterfaceType.AutoDispatch), _
	DefaultBindingProperty("Rtf"), Description("DescriptionRichTextBox"), _
	ComVisible(True), Docking(DockingBehavior.Ask), _
	Designer("System.Windows.Forms.Design.RichTextBoxDesigner, _
	System.Design, Version=4.0.0.0, Culture=neutral, _
	PublicKeyToken=b03f5f7f11d50a3a")> _
Public Class dbRTBox
    Inherits RichTextBox

    <Bindable(True), RefreshProperties(RefreshProperties.All), _
	SettingsBindable(True), DefaultValue(""), Category("Appearance")> _
    Public Overloads Property Rtf As String
        Get
            Return MyBase.Rtf
        End Get
        Set(ByVal value As String)
            MyBase.Rtf = value
        End Set
    End Property

End Class 

As you can see, the class has one property (Rtf) that hides the base.Rtf property. We did this just so we can put the tags above the property to let the designer know that we want to allow databinding on this property.

The code...

Bindable(true)

...is the key line of code that makes this all work. This tag tells the designer that you want to bind to this property.

Since we will almost always want to bind to the Rtf property, we also want to add a tag to the class...

C#

 [ClassInterface(ClassInterfaceType.AutoDispatch), 
	DefaultBindingProperty("Rtf"), Description("DescriptionRichTextBox"), 
	ComVisible(true), Docking(DockingBehavior.Ask), 
	Designer("System.Windows.Forms.Design.RichTextBoxDesigner, 
	System.Design, Version=4.0.0.0, Culture=neutral, 
	PublicKeyToken=b03f5f7f11d50a3a")]    

VB

 <ClassInterface(ClassInterfaceType.AutoDispatch), 
	DefaultBindingProperty("Rtf"), Description("DescriptionRichTextBox"), 
	ComVisible(True), Docking(DockingBehavior.Ask), 
	Designer("System.Windows.Forms.Design.RichTextBoxDesigner, 
	System.Design, Version=4.0.0.0, Culture=neutral, 
	PublicKeyToken=b03f5f7f11d50a3a")> _ 

In this tag, we utilize the default RichTextBox tags, but we add the tag DefaultBindingProperty("Rtf"), so when we drag a field from the DataSources window onto the dbRTBox control, it will bind directly to the Rtf property, rather than the Text property.

In the sample code, Form1 has a sub class called DataItem.

public class DataItem
{
    public DataItem(int i)
    {
        using (RichTextBox rtb = new RichTextBox())
        {
            rtb.Text = "Item #" + i.ToString();
            Key = rtb.Rtf;
        }
        Value = i;
    }

    public string Key { get; set; }
    public int Value { get; set; }
}  

In this class, you can see in the constructor we simply create an RTF formatted string (using a RichTextbox :-D ) that simply contains the Item Number of the current item, and store it into the Key property.

The constructor of Form1 simply loads a List<DataItem> that contains 20 items into the Form1_DataItemBindingSource. Using the 'Next' and 'Prev' buttons on the form, you can navigate through the items in the binding source and see that the actual items are bound to the Rtf property of the control, not the Text property.

Points of Interest

The best part of this control (other than its simplicity) is that you can perform your databinding from within the WinForms designer, so even the most inexperienced programmer can easily databind rich text fields in just moments using nothing but the mouse.

History

  • Created 6/24/2010
  • Updated 6/24/2010 to include VB code

License

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

About the Author

Mike Baldini
Software Developer (Senior) North 40 Systems
United States United States
Member
Senior Software Engineer / Program Manager for Office Tools Professional.
 
I have been a professional software engineer since 2007, but have been hacking video games and automotive ECUs since the late 1990's.
 
I mainly write in c# and VB.net in Visual Studio, but am also comfortable in Java and c/c++ in eclipse.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membergrunsho3 Jan '13 - 7:13 
It's just what I was looking for. Thank you very much, good work!
QuestionUnable to get richtextBox to work as presentedmemberwjprice15 Aug '11 - 3:37 
I am new at this but i performed the following steps:
 
1. Included your dbRTBjox.cs class into my project (using the version you provided with the comment whereby validation is performed for already existing plain text data in the database).
2. Compiled
3. Created a datasource using the wizard
4. Dragged one field from the datasource (as a richtext box)
5. Allowed the bingingnavigator, dataset, bindingsource, and tableadapter to be auto created
6. Compiled
7. Ran the project in debug mode (f5)
8. Pasted rich text (from Word) into the only field
9. Saved and closed the program
10..Re-ran the program
11. The richtext field DID NOT contain the formatted text.
 

What did i do wrong?
Thank you,
Willie
QuestionNot Working With Typed-Dataset In VS2008?memberpointeman121 Jul '11 - 13:03 
I'm using your code exactly as-is and still application hangs on opening everytime I set the DataBinding property to my Typed-DataSet (data type String);
 
Q. What data type should the typed-dataset be?
AnswerRe: Not Working With Typed-Dataset In VS2008?memberMike Baldini21 Jul '11 - 13:19 
We have been using a nearly identical version of this control for quite a while now, and we haven't run into an issue with it hanging.
 
We generally use something like this:
DataBound RichTextBox initialization
        Me.txtNotes.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.ProjectAssignmentManagerBindingSource, "Note", True))
 
BindingSource initialization where ProjectAssignmentManager is simply a List<T> (T being your individual data object)
        Me.ProjectAssignmentManagerBindingSource.DataSource = GetType(ProjectAssignmentManager)
 

Are you binding directly to a System.Data.DataSet? Or are you using some derivative of IEnumerable?
"Reality is merely an illusion, albeit a very persistent one."
-Albert Einstein

GeneralIt needs .Net 4memberkillerbranch4 Jun '11 - 7:15 
Could you post src for 3 or 3.5 please?
GeneralRe: It needs .Net 4memberMike Baldini4 Jun '11 - 8:47 
It doesn't actually require any .net 4 components so you should be able to simply change the target framework in the project properties. I am using a slightly modified version of this in my production code that is on .net 3.5
Thumbs Up | :thumbsup:
"Reality is merely an illusion, albeit a very persistent one."
-Albert Einstein

GeneralBinding to an existing field containing plain textmemberRV Williams28 Jun '10 - 20:02 
Excellent work and thanks for sharing.
Is it possible to modify this control so that it will bind to existing database fields that already contain plain text? I'm thinking of the scenario where through the databinding process the existing plain text could be 'loaded' into the control and when modified by the UI it can then be saved back to the field as rtf. So essentially, any plain text fields get automatically converted to rtf in the background.
GeneralRe: Binding to an existing field containing plain textmemberMike Baldini29 Jun '10 - 8:51 
I know exactly what you are talking about. We have the same dilemma with some fields being a mixture of RTF in some records, and plain text in others.
 
So I suppose you could do a bit of validation on the property...
C#:
        [Bindable(true), RefreshProperties(RefreshProperties.All), SettingsBindable(true), DefaultValue(""), Category("Appearance")]
        new public string Rtf
        {
            get
            {
                return base.Rtf;
            }
            set
            {
                if (IsRTF(value))
                {
                    base.Rtf = value;
                }
                else
                {
                    base.Text = value;
                }
            }
        }
 
        bool IsRTF(string s)
        {
            bool ret = false;
            try
            {
                using (RichTextBox rtb = new RichTextBox())
                {
                    rtb.Rtf = s;
                    ret = true;
                }
            } catch (Exception){}
            return ret;
        }
 
VB:
    <Bindable(True), RefreshProperties(RefreshProperties.All), SettingsBindable(True), DefaultValue(""), Category("Appearance")> _
    Public Overloads Property Rtf As String
        Get
            Return MyBase.Rtf
        End Get
        Set(ByVal value As String)
            If IsRTF(value) Then
                MyBase.Rtf = value
            Else
                MyBase.Text = value
            End If
        End Set
    End Property
 
    Function IsRTF(ByVal s As String) As Boolean
        Dim ret As Boolean = False
        Try
            Using rtb As New RichTextBox
                rtb.Rtf = s
                ret = True
            End Using
        Catch ex As Exception
        End Try
        Return ret
    End Function
Developer

GeneralMy vote of 5memberArchKaine28 Jun '10 - 15:04 
Clearly written, nice code, and easily understandable while still getting to the meat of the matter. Nice job.
JokeRe: My vote of 5memberMike Baldini28 Jun '10 - 15:38 
Thank you!
 
this is my first article, and I do have a hard time trying to convey my thoughts to other people. I had spent the first part of the day showing a new kid at work how to databind objects on a form. What was funny was that the form I picked to demonstrate the technique was the 'Default Invoicing Paragraphs' dialog, which has 4 RichTextBoxes on it. And since the base RichTextBox cannot be bound to the Rtf property, everything I was telling the new kid was conflicting with what I was showing him on the screen.
 
I felt stupid for trying to teach him a new concept by choosing a form that had absolutely nothing to do with the subject (just because Microsoft was too lazy to add a few lines of code for Rtf binding Laugh | :laugh: just kidding Cool | :cool: ), so I had to remedy the lacking features in the RichTextBox and try to show him the concept again the next day. Big Grin | :-D
Developer

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 24 Jun 2010
Article Copyright 2010 by Mike Baldini
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid