Tuesday, April 20, 2010

Editing Rtf file

Sometimes there is need to edit an .rtf file. To my knowledge, exept the PIA Interop word, there is no free and effective tools to edit such a file. The word Interop problem is performance and also their integration in web applications which often causes problems.


I discovered by accident that the WPF RichTextBox control (exept the fact that it allows to read and write a .RTF document) allows you to edit an .RTF document programmatically. The purpose of this article is to see the possibilities offered by this control.


For this, I created a WPF application to read an .RTF document, insert a row in a table, edit and add text in a paragraph. The interface looks like this:



First, open the .RTF document:


' Open the rtf document
Public Function OpenRtf() As Boolean
' Check the file path
If Not File.Exists(Me._rtfFilePath) Then Throw New ArgumentException("The rtf file does not exist")
' With two TextPointer positions as the beginning and end positions for the new Range
Dim range As New TextRange(Me._rtb.Document.ContentStart, Me._rtb.Document.ContentEnd)
' Exposes a stream around the .RTF File for opening the file
Using fStream As New FileStream(Me._rtfFilePath, FileMode.OpenOrCreate)
' Load the current selection (In this case all the .Rtf file content)
range.Load(fStream, DataFormats.Rtf)
End Using
Return True
End Function

The function to insert a row in a table in the document:


' Insert a row at a specified table index and rows index
Public Function InsertRow(ByVal tableIndex As Integer, ByVal rowIndex As Integer) As Boolean
Dim i As Integer
Dim table1 As Table = Nothing
For j = 0 To Me._rtb.Document.Blocks.Count - 1
' Is the current object type a Tabel ?
If Not TypeOf (Me._rtb.Document.Blocks(j)) Is Table Then Continue For
i += 1
' Is the current table a second one ?
If i < tableIndex Then Continue For
' Get the table at index = tableIndex
table1 = Me._rtb.Document.Blocks(j)
Exit For
Next
' Is there no table in the Rtf file ?
If table1 Is Nothing Then Return False
' Add a new row after a specified row index
table1.RowGroups(0).Rows.Insert(rowIndex, New TableRow())
Dim currentRow As TableRow = table1.RowGroups(0).Rows(rowIndex)
' Global formatting for the row.
currentRow.FontSize = 12
currentRow.FontWeight = FontWeights.Normal
' Add cells with content to the new row.
currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Paris"))))
currentRow.Cells.Add(New TableCell(New Paragraph(New Run("France"))))
currentRow.Cells.Add(New TableCell(New Paragraph(New Run("$50,0"))))
currentRow.Cells.Add(New TableCell(New Paragraph(New Run("$50,0"))))
currentRow.Cells.Add(New TableCell(New Paragraph(New Run("$5,0"))))
' Bold the cells content.
For i = 0 To currentRow.Cells.Count - 1
currentRow.Cells(i).FontWeight = FontWeights.Bold
currentRow.Cells(i).SetValue(TableCell.BorderThicknessProperty, New Thickness(1D))
currentRow.Cells(i).SetValue(TableCell.BorderBrushProperty, Brushes.Black)
Next
Return True
End Function

The "System.Windows.Documents.Block" object is useful to take all document objects, so we get a BlockCollection. Table, Paragraph, List and others inherits from Block Object


Then, to change a paragraph and edit it we do the following:


' Edit a specified paragraph
Public Function EditParagraph(ByVal paragraphIndex As Integer) As Boolean
Dim i As Integer
Dim pgh As Paragraph = Nothing
For j = 0 To Me._rtb.Document.Blocks.Count - 1
' Is the current object type a Tabel ?
If Not TypeOf (Me._rtb.Document.Blocks(j)) Is Paragraph Then Continue For
i += 1
' Is the current paragraph a second one ?
If i < 7 Then Continue For
' Get the third paragraph
pgh = Me._rtb.Document.Blocks(j)
Exit For
Next
' Is there no paragraph in the Rtf file ?
If pgh Is Nothing Then Return False
' Create two TextPointers that will specify the text range the Span will cover
Dim myTextPointer1 As TextPointer = pgh.ContentStart.GetPositionAtOffset(10)
Dim myTextPointer2 As TextPointer = pgh.ContentEnd.GetPositionAtOffset(-5)
' Create a Span that covers the range between the two TextPointers.
Dim mySpan As Span = New Span(myTextPointer1, myTextPointer2)
mySpan.Background = Brushes.Red
' Add some text
pgh.Inlines.Add(New Run(". Some others informations can be found here: "))
' Add a link
Dim run3 As New Run("MSDN")
Dim hyperl As New Hyperlink(run3)
hyperl.NavigateUri = New Uri("http://msdn.microsoft.com/fr-fr/library/ms754030%28v=VS.100%29.aspx")
pgh.Inlines.Add(hyperl)
Return True
End Function

Finally, we save the document:


' Save the rtf document
Public Function SaveRtf() As Boolean
'initializes a new instance of TextRange
Dim range As New TextRange(Me._rtb.Document.ContentStart, Me._rtb.Document.ContentEnd)
' Exposes a stream around the .RTF File for opening the file
Using fStream As New FileStream(Me._rtfFilePath, FileMode.OpenOrCreate)
' Save the current selection (In this case all the document)
range.Save(fStream, DataFormats.Rtf)
End Using
Return True
End Function

In this article, we reviewed how to edit an .RTF document without using a third-party tool.
The following links are useful for understanding the extent of possibiltés offered by the "System.Windows.Documents" namespace:


MSDN "System.Windows.Documents Namespace"
Kirupa.Chinnathambi Article


zip WpfRTBToRTF.zip - 100 Kio

No comments:

Post a Comment