Ged Mead

Ged Mead (XTab) is a Microsoft Visual Basic MVP who has been working on computer software and design for more than 25 years. His journey has taken him through many different facets of IT. These include training as a Systems Analyst, working in a mainframe software development environment, creating financial management systems and a short time spent on military laptop systems in the days when it took two strong men to carry a 'mobile' system.
Based in an idyllic lochside location in the West of Scotland, he is currently involved in an ever-widening range of VB.NET, WPF and Silverlight development projects. Now working in a consultancy environment, his passion however still remains helping students and professional developers to take advantage of the ever increasing range of sophisticated tools available to them.
Ged is a regular contributor to forums on vbCity and authors articles for DevCity. He is a moderator on VBCity and the MSDN Tech Forums and spends a lot of time answering technical questions there and in several other VB forum sites. Senior Editor for DevCity.NET, vbCity Developer Community Leader and Admin, and DevCity.NET Newsletter Editor. He has written and continues to tutor a number of free online courses for VB.NET developers.
View all articles by Ged Mead...
Introduction
In the previous part, we looked at inserting a XAML FlowDocument into a WPF RichTextBox.
I mentioned there that although in future you may prefer to build your content using XAML, there may still be times when you want to use RichTextFormat (RTF).
In this part we will begin by looking at how to populate a RichTextBox with an RTF document.
The RTF Document
For the purposes of this article I created a simple RTF document saved as RTFDocument.rtf, using Microsoft WordPad. As you will see from the screenshot, it includes several of the main text formatting features that you would normally expect to be available.

Loading The RichTextBox
The WPF RichTextBox has a Loaded event and this would be a good place to put the code which then populates it with our RTF content. I'll show the code first and then walk through it.
Dim fs As FileStream
Private Sub rtbRTF_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles rtbRTF.Loaded
' Load RTB with text from RTF file
Dim strDataFormat As String = DataFormats.Rtf
fs = New FileStream("RTFDocument.rtf", FileMode.Open, FileAccess.Read)
' Create a TextRange that comprises the start and end points of the RichTextBox text
Dim tr As New TextRange(rtbRTF.Document.ContentStart, rtbRTF.Document.ContentEnd)
tr.Load(fs, strDataFormat)
fs.Close()
fs.Dispose()
End Sub
In the absence of a dedicated reader, such as the XAMLReader that we used in the previous part, we have to use a TextRange object from the System.Windows.Documents class as our means of piping the data through a FileStream into the RichTextBox.
I will go through the above code a line at a time, because although it's not complex it is in some ways a bit unusual.
Dim strDataFormat As String = DataFormats.Rtf
The DataFormats class offers an assortment of file type names that can be used to identify data formats - RTF being one of these. In this example, the file type selection (rtf) is saved to a string that will be used later.
fs = New FileStream("RTFDocument.rtf", FileMode.Open, FileAccess.Read)
This FileStream picks up the content from the rtf file and will be used shortly to pipe it into the RichTextBox.
Dim tr As New TextRange(rtbRTF.Document.ContentStart, rtbRTF.Document.ContentEnd)
For the TextRange to be useful it needs to be told where it should get its content from, plus two TextPointers - one each for the start point and end points of the required selection. In this particular case we set it to be the start and end points of the current document being housed by the RichTextBox.
If you've just done a double-take or scratched your head, I'll not be at all surprised. The RichTextBox doesn't actually appear to have a document in it yet ! So, yes, it does seem a bit weird to be apparently scraping content from an empty RichTextBox. However what is really happening here is that the TextRange is being given the start and end points of a document, acting as placeholders for those two TextPointers I mentioned earlier that are required by the TextRange's constructor.
The result is that currently the TextPointers are the beginning and end of whatever document happens to be in the RichTextBox, even though at the moment it is an empty document. It all makes more sense when we move to the next line, where we meet the TextRange's Load method.
tr.Load(fs, strDataFormat)
This method takes the FileStream (which you will remember is the conduit to the rtf file I created in MS Word) and the DataFormats type of rtf that I set at the start of the code snippet. So the TextRange is now loaded with the content from the RTFDocument.rtf file. Finally, because we have set the TextRange to be placed between the start and end points of the RichTextBox's Document, we see our rtf file displayed in the RichTextBox.
The last two lines of the snippet are standard housekeeping to clear up after the FileStream the old fashioned way.
Saving the RTF File
Given the scenario that you need to display an rtf file in the RichTextBox, it's possible that you might sometimes need to save any changes that your users have made.
The following code will do this and in fact it will assess whether the content in the RichTextBox is either rtf or XAML and will save it appropriately. The original C# code comes from Jessica Fossler (jfo) who worked on the team in the early days of WPF, so I take no credit for it, other than converting it to VB. Jessica also wrote an excellent guide to help developers transition from Windows Forms to WPF Windows, much of which is still very useful.
Private Shared Sub SaveFile(ByVal filename As String, ByVal richTextBox As RichTextBox)
If String.IsNullOrEmpty(filename) Then
Throw New ArgumentNullException()
End If
' Open the file for writing
Using stream As FileStream = File.OpenWrite(filename)
' create a TextRange to contain the entire document
Dim documentTextRange As New TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd)
' Sniff out what data format you've got
Dim dataFormat As String = DataFormats.Text
Dim ext As String = Path.GetExtension(filename)
If [String].Compare(ext, ".xaml", True) = 0 Then
dataFormat = DataFormats.Xaml
ElseIf [String].Compare(ext, ".rtf", True) = 0 Then
dataFormat = DataFormats.Rtf
End If
' Save it
documentTextRange.Save(stream, dataFormat)
End Using
End Sub
Summary
If you need to view, edit or save rtf formatted data in a WPF application, the above code will suit your needs.
In the next part, I plan to take a second look at FlowDocuments, but this time using more sophisticated viewers than the RichTextBox and also using them to display content that is not restricted to text or text and images.