DevCity.NET - http://devcity.net
Windows Presentation Foundation: Flow Documents (Part 2)
http://devcity.net/Articles/356/1/article.aspx
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.

 
by Ged Mead
Published on 9/15/2008
 

  In Part 1, you saw how easy it is to populate a WPF RichTextBox with a XAML FlowDocument.  If you've ever previously struggled with trying to force a RichTextBox to accept an image - and place it exactly where you want it - in Windows Forms, then you'll welcome this new tool.

 However, for legacy reasons you might want to populate the RichTextBox with content that has been saved in RTF format.  In this part we will look at how that can be achieved.


Using RTF in a WPF RichTextBox

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.

 

RTF Document

 

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.

Code Copy
   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.

Code Copy
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.   

Code Copy
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.  

Code Copy
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.

Code Copy
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.

    

Code Copy
    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.