WPF RichTextBox With Two Way DataBinding

by Shawn Duggan on 02/08/2009

In an application I’m currently writing my users will be creating many text notes and I wanted to allow for the user to create nicely formatted documents, as well as having the ability for fine-grained control over printing options.  Enter the RichTextBox – it is similar to a TextBox, but provides more advanced text formatting options to the user.  Enabling the advanced editing features is trivial (read up on the available Editing Commands), literally in minutes you can create a WYSIWYG editor.   Where things get sticky is when you start talking about databinding.

The RichTextBox stores the text in its Document property which is of type FlowDocument.  It isn’t a dependency property, nor does it implement INotiftyPropertyChanged so you can’t bind directly to it.  This is a problem.  In my application I want my users to create richly formatted documents which are added to a Notes collection on my entity and then have each note persisted as a string in my database.

I decided the best way to go would be to subclass the RichTextBox, and expose a DependencyProperty to handle the binding.  I’d then need some plumbing internally to keep things in sync.  Before I plunged headfirst into my own implementation, I spent a little time on Google to see how others have approached the problem.  I found many people hoping to do the same thing I was, but not any complete solutions.  I did find a MSDN forum post which had a code snippet that looked like a good place to start, and I also found some sample code for a WYSIWYG editor, so I cobbled the 2 together in my new WPFControls project and I was off and running.

Getting the Two-Way databinding working did turn out to be more of a chore than I’d hoped, but using the IValueConverter interface I was eventually able to bind a string property on a domain entity to the Document property on a RichTextBox.  I decided to wrap the implementation up in its own UserControl for reuse, so in the end my domain entity is bound to a string DP on the UC, and the Document property on the RichTextBox is bound to this same string property on the UC using IValueConverter.

To use the control in a project you first need to reference it in your project, and then in xaml you can reference it like this:

   1: xmlns:WPFControls="clr-namespace:BlueTango.WPFControls;assembly=BlueTango.WPFControls"

and then to use it:

   1: <WPFControls:TextEditor
   2:                     SpellCheckIsEnabled="True"
   3:                     AcceptsTab="True"
   4:                     Document="{Binding ElementName=lstNotes, Path=SelectedItem.Description, Mode=TwoWay}" />

I added a couple of properties on the control itself to illustrate that it easy to still have control over the inner wrapped RTB.  You can see in my sample above I have it bound to a ListBox control which has a list of Notes.  The Description property is the string holding the xaml of the FlowDocument.

I have included a rough sample project you can use to create your own control for your projects.  Enjoy!

BlueTango.WPFControls.zip (2712)

UPDATE:   A reader contributed this code a while back…

From Abbott Fleur and Dan Vanderboom: “I’m expanding your BindableRichTextBox control to allow linq-sql binding to db text source. I’m planning on using an existing routine I’ve written that loads the RTB based on the ip format and saves based on a SaveAs (DataFormats) property. ”

While I have not tried this code myself – here it is.  Thanks Abbott and Dan!

BoundRichTextBox.zip (2037)

While comments are welcome, please note that I am unable to offer help or support for using this update or the original code.  It is provided “as-is” without warranty or guarantees.

{ 49 comments… read them below or add one }

1 Daniil Harik March 31, 2009 at 7:25 am

Thank You!

Very neat solution :)

Saved me a lot of time

2 Christo April 14, 2009 at 2:30 am

I’m not able to use your solution when reading the string from a db.

The string I get from the db is

{\rtf1\ansi\deff0{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\fswiss\fcharset0 Arial;}}
{\*\generator Msftedit;}\viewkind4\uc1\pard\lang1033\i\f0\fs36 bla bla bla\i0\f1\fs20\par

which is copied out of a rtf file.

I tried to modify your converter by setting the DataFormats.Rtf. The xaml code should be fine, because I get the correct value for value in the converter when I step through, but the flowDocument does not display correctly.

Any ideas?


3 Christo April 14, 2009 at 5:56 am

Truth be told, I got it to work, but I have no idea how I did it. But thanx anyway.


4 Abbott Fleur May 12, 2009 at 11:44 am

In StringTOXAMLConverter I get the following error at:

text.Load(stream, DataFormats.Xaml);

The DB query was fine and the data looks good in var text.

THanks for any help – a WPF newbie

System.Windows.Markup.XamlParseException occurred
Message=”Data at the root level is invalid. Line 1, position 1.”
at System.Windows.Markup.XamlReaderHelper.RethrowAsParseException(String keyString, Int32 lineNumber, Int32 linePosition, Exception innerException)
at System.Windows.Markup.XamlReaderHelper.Read(XamlNode& xamlNode)
at System.Windows.Markup.XamlParser.ReadXaml(Boolean singleRecordMode)
at System.Windows.Markup.TreeBuilderXamlTranslator._Parse()
at System.Windows.Markup.XamlParser.Parse()
at System.Windows.Markup.XamlTreeBuilder.ParseFragment()
at System.Windows.Markup.TreeBuilder.Parse()
at System.Windows.Markup.XamlReader.XmlTreeBuildDefault(ParserContext pc, XmlReader reader, Boolean wrapWithMarkupCompatReader, XamlParseMode parseMode, Boolean etwTracingEnabled)
at System.Windows.Markup.XamlReader.Load(XmlReader reader)
at System.Windows.Documents.TextRange.set_Xml(String value)
at System.Windows.Documents.TextRangeBase.Load(TextRange thisRange, Stream stream, String dataFormat)
at System.Windows.Documents.TextRange.LoadVirtual(Stream stream, String dataFormat)
at System.Windows.Documents.TextRange.Load(Stream stream, String dataFormat)
at BlueTango.WPFControls.StringToXamlConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture) in E:\1Data\1VA\Projects\Surveys\BlueTango.WPFControls\StringToXamlConverter.cs:line 28
InnerException: System.Xml.XmlException
Message=”Data at the root level is invalid. Line 1, position 1.”
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Windows.Markup.XmlCompatibilityReader.Read()
at System.Windows.Markup.XamlReaderHelper.Read(XamlNode& xamlNode)

5 Shawn May 16, 2009 at 11:14 am

Abbot – it looks to me as if your Xaml stored in the string is not valid for a FlowDocument. Try saving something using the code then viewing it.

6 Nigel Findlater May 18, 2009 at 10:34 am

Hallo Shawn,

I really like this control, but I am having the same problem as Christo. when I try to load a xaml file I get the error Message=”Data at the root level is invalid. Line 1, position 1.”

Any idea’s?


7 Shawn May 18, 2009 at 6:13 pm

Nigel – what are you trying to load? Is it your own xaml, or something the control saved? The format can be tricky to create on your own. Try saving something from the control then loading it.

8 Nigel Findlater May 19, 2009 at 3:33 am

Hallo Shawn,

Thanks for the reply. I tried creating a xaml file from your control but I failed. So I created one using some code from http://msdn.microsoft.com/en-us/library/aa970779.aspx

void SaveXamlPackage(string _fileName)
TextRange range;
FileStream fStream;
range = new TextRange(richTB.Document.ContentStart, richTB.Document.ContentEnd);
fStream = new FileStream(_fileName, FileMode.Create);
range.Save(fStream, DataFormats.XamlPackage);

I was able to releod the xaml using

void LoadXamlPackage(string _fileName)
TextRange range;
FileStream fStream;
if (File.Exists(_fileName))
range = new TextRange(richTB.Document.ContentStart, richTB.Document.ContentEnd);
fStream = new FileStream(_fileName, FileMode.OpenOrCreate);
range.Load(fStream, DataFormats.XamlPackage);

But when I read this file into a string and bound this to your control it failed.

I will keep on looking to see where the problem is, if I find a solution I will let you know…

have a nice day…


9 Nigel Findlater May 19, 2009 at 3:57 am

Hallo Shawn,

I have found my mistake.

Instead of
range.Save(fStream, DataFormats.XamlPackage);

I should have used:
range.Save(fStream, DataFormats.Xaml);

Thanks for your time, I really like your control…

have a nice day…


10 Shawn May 19, 2009 at 7:04 am

Nigel – glad you found it. My use case for the control was persisting the xaml to a database, not reading/writing to a file.

11 Franklin May 26, 2009 at 11:55 am

There is something wrong with your control.

Create a new WPF project, reference your dll, add your control, create a class with one string property, create instance of that and bind to datacontent of window, bind your control to it, run. It doesn’t save anything to the property when editing.

12 Shawn May 31, 2009 at 2:13 pm

@Franklin – Sorry you are having issues, but the control does indeed work.

13 Leszek July 9, 2009 at 7:49 am


the control is very nice. I have had some problems with binding but after changing from xaml to rtf is is working almost fine. The issue I am facing is situation when you bind on load with property that is null or string empty. Then the binding is not working at all.

14 Andy M August 6, 2009 at 11:35 am

Thanks for this Shawn. Very helpful. I did find one quirk. Hooking ValueChanged on the DependencyPropertyDescriptor prevents GC of the RTB. By removing the DependencyPropertyDescriptor delegate and using PropertyChangedCallback on the Document DependencyProperty instead, there is no more hard reference, allowing the whole thing to get evicted:

/// Identifies the dependency property.
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register(“Document”, typeof(FlowDocument), typeof(BindableRichTextBox),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(Document_PropertyChanged)));

private static void Document_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
BindableRichTextBox b = (BindableRichTextBox)d;

private void UpdateBaseDocument()
base.Document = (FlowDocument)GetValue(DocumentProperty);

15 Shawn August 6, 2009 at 12:33 pm

Thanks Andy – I will definitely check that out!

16 Gal August 11, 2009 at 2:16 am

Got the same problem as Franklin:
I use a string property to bind to the Document property of the Rich Text Box, and nothing..
Any ideas?

17 Gal August 11, 2009 at 2:53 am

OK, got it!
In order to bind a string to the “Document” property, that comes from a string property in another class, I changed some things in the “StringToXamlConverter”:
In the Convert method, instead of:
text.Load(stream, DataFormats.Xaml);
I use:
text.Load(stream, DataFormats.Rtf);

And in the ConvertBack method, instead of:
range.Save(stream, TextDataFormat.Xaml.ToString());
I use:
range.Save(stream, TextDataFormat.Text.ToString());

Than, in the XAML file:

And it works.
The only problem is that you can’t use UpdateSourceTrigger=PropertyChanged,
only Lost Focus, but that’s fine with me.
Thanks Shawn!

18 Gal August 11, 2009 at 2:56 am

Somehow the xaml file code didnt make it, so in words:
Used the converter in the “Documenet” binding deceleration.

19 Abbott Fleur September 1, 2009 at 2:06 pm

I’m expanding your BindableRichTextBox control to allow linq-sql binding to db text source. I’m planning on using an existing routine I’ve written that loads the RTB based on the ip format and saves based on a SaveAs (DataFormats) property. If this is of interest to you I’ll send you my changes.

I’m hoping that this will allow me to use the control in place of a normal textbox within a datagrid.


20 Jean-Marie Pirelli September 7, 2009 at 8:43 am

Thanks for the code.
I had the problem of the string property bound to BindableRichTextBox.Document being always null. I changed the Convert method of StringToXamlConverter to return an empty FlowDocument if the value parameter is null. Now, I get the desired behavior.


21 Eric October 20, 2009 at 5:23 pm

I can’t seem to get it to work. I have the following XAML, but when I type anything into the RTF control, the bound control isn’t changing:

22 Eric October 20, 2009 at 11:10 pm

Ok, I figured out how to bind to another WPF control, but I can’t seem to bind to a property in the DataContext object. Is there a difference here?

23 Sam December 22, 2009 at 1:20 pm

Hi Shawn

I’ve got the same problem like Eric.
How can I bind the Control to a property of my DataContext object without a Control between?

24 Michael January 5, 2010 at 6:54 am

Hey Shawn

Could you post an example of how to use your control for databinding.
I seem to have difficulites using it.


25 Shawn Duggan January 5, 2010 at 7:12 am

@Sam and @Michael – I have a sample a person sent me…I’ll dig it up and post it here in the next couple of days for you.

26 Michael January 5, 2010 at 7:17 am


I think my problem lies within the coupling between the code behind and the xaml file.
My general purpose is to use it in a MVVM application, but neither does it work, if I just do some random stuff in the xaml.cs file.

27 Michael January 15, 2010 at 3:32 am

Hi Shawn

Have you digged up something :)

28 Shawn Duggan January 17, 2010 at 6:09 pm

@Sam and @Michael – I have updated the post with a new attachment.

29 Michael January 20, 2010 at 5:19 am

Hi Shawn

I will try and fiddle with the new attachment, but what I was looking for was an example of how to data binding the RTB control to a property of my own e.g. a string.
If any one else has such an example I would be very greatful

30 Muaath Jamil February 4, 2010 at 5:08 am

Hi Shawn,,

Your control is soo great,,
I get a very huge benifit from it…

now i’m trying to use your control (TextEditor) inside my UserControl…
But I faced a very strange behaviour..
when I try to edit the text inside the TextEditor:
The Line In The Control accept only one character and continue the next character in the next line (although the rest of the line is empty)..
for exampe..
when i try to write (Hello World!!) it will displayed as:


— I Tried alot of things but witout any success..
When I use it inside the page or window directly it works fine,, the problem occure only when using the control inside a UserControl..

I Appreciate any help..
Thank You alot *_*

31 Shawn Duggan February 5, 2010 at 11:01 pm

@Muaath – I’m glad you like the control. I’m not sure what you are attempting to do, but wrapping it in a usercontrol isn’t really necessary – it is its own control already. Good luck!

32 Muaath Jamil February 7, 2010 at 1:12 am

Hi Shawn..

I’m tryng to make a usercontrol to use it as a ListBox Item Template..
each item will display its details plus a RitchText Editor for the user to put some notes on each item..

I wish you get what i want to acheive *_*

33 Muaath Jamil February 7, 2010 at 3:40 am


I Found A solution,, It seems a .net bug..
I put ScrollViewer.CanContentScroll=”True” for the ListBox..
And It Works Fine *_*

Now How Can I Put Your Control as a ReadOnly?
This Property Is Not SHown In Your Control although it is available in RitchTextBox…


34 Shawn Duggan February 7, 2010 at 5:35 pm

@engo2000a It should be a relatively simple matter to expose another property on the control to use. Look at how I implemented the SpellCheckIsEnabled property. Good luck!

35 Muaath Jamil February 8, 2010 at 12:20 am

Done *_*
Thanks Alot *_*

36 Jaco Louw March 17, 2010 at 7:39 am

Hi Shawn,

Thanks for a really cool control. I have a problem with the height of the actual RichTextBox inside the control. If I make the height of user control big, the textbox still remains only big enough for one line. How can I change the hight of the textbox?


37 Jaco Louw March 17, 2010 at 7:51 am

Nevermind my previous query. I’ve discovered the textbox grows as you add lines. I have a different problem though. When the textbox gets too large, it doesn’t create a scrollbar. Is there an easy way to do this?

38 anup May 17, 2010 at 9:53 am

I got an issue where value of RichTextBox is initilized for the first time.
After which it never get updated.

Sometime control becomes invisible.

I am using MVVM pattern for the same
Can you please help me

39 Shawn Duggan May 19, 2010 at 8:53 pm

@anup – I don’t have enough detail to give you any ideas to try.

40 Anup May 21, 2010 at 9:08 am

Hi ,
I tried to use the control attached. IT works well initially for the first time,
I have added u’r control inside another usercontrol (CustomEditor.Xaml) which is used for MVVM pattern.
I have exposed the Document property form u’r control so that i can set it through my ViewModel. Now for the first time binding this control workds very well, but when i try to rebind it again, sometimes control simply hangs up doing nothing.
When i checked inside the converter code, conversion is happening correctly & Document is gettting re-assigned to base.Document property of the RichTextBox. But on the UI text is not getting re-freshed.

Can you please tell me how can i overcome this behaviour?

41 Shawn Duggan May 24, 2010 at 8:34 am

@Anup – I think it is something to do with the bindings between your outer control and my nested inner control. Good luck!

42 Miguel Freire September 8, 2010 at 11:34 am
43 http://www.pethke.nl/panicaway333825 March 5, 2014 at 11:02 pm

I am actually happy to read this webpage posts which consists
of tons of valuable facts, thanks for providing such statistics.

44 http://s.dlehr.at/PanicAway136429 March 16, 2014 at 6:16 am

Thanks for a marvelous posting! I certainly enjoyed reading it, you happen to be a great author.
I will be sure to bookmark your blog and may
come back at some point. I want to encourage one to continue your great job, have a nice holiday weekend!

45 anxiety March 17, 2014 at 8:09 pm

Hello there! This post couldn’t be written any better!
Reading through this post reminds me of my old room mate!
He always kept talking about this. I will forward this article to him.
Fairly certain he will have a good read. Many thanks for

46 anxiety attack wiki May 16, 2014 at 7:34 pm

After I originally left a comment I appear to have clicked the -Notify me when new
comments are added- checkbox and now each time a comment is added I recieve four emails with the exact same comment.
There has to be a way you can remove me from that service?
Many thanks!

47 google adwords editor June 29, 2014 at 9:05 pm

My partner and I stumbled over here from a different page and thought I might as well check things
out. I like what I see so now i am following you.
Look forward to finding out about your web page yet again.

48 new years firework July 14, 2014 at 9:06 pm

Wonderful beat ! I wish to apprentice while you amend your site, how can i
subscribe for a blog website? The account aided me a acceptable deal.

I had been tiny bit acquainted of this your broadcast provided
bright clear concept

49 calculer le poids idéal July 24, 2014 at 12:13 am

Actuellement, vous avez statué ceci adéquatement!

Leave a Comment

{ 2 trackbacks }

Previous post:

Next post: