Modifying the Content
You saw how to modify the content by inserting text in the previous section. In this section, suppose you work for a company called DEVX, and legal is demanding that all company documents include the trademark text
(tm) after every occurrence of the word
DEVX in a document. You can modify the content of a RichTextBox quickly and simply to achieve this by using regular expressions. For example, the following C# code would execute whenever the user saves the document:
TextRange tr = new TextRange(
XAMLRichBox.Document.ContentStart,
XAMLRichBox.Document.ContentEnd);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
tr.Save(ms, DataFormats.Xaml);
string xamlString = ASCIIEncoding.Default.GetString(ms.ToArray());
System.Text.RegularExpressions.Regex findDEVX =
new System.Text.RegularExpressions.Regex("DEVX(?![\\(TM\\)])");
xamlString = findDEVX.Replace(xamlString, "DEVX(tm)");
System.IO.MemoryStream msOut = new System.IO.MemoryStream();
System.IO.StreamWriter sw = new System.IO.StreamWriter(msOut);
sw.Write(xamlString);
sw.Flush();
msOut.Seek(0, System.IO.SeekOrigin.Begin);
tr.Load(msOut, DataFormats.Xaml);
This example extracts the XAML from the RichTextBox by creating a TextRange covering the whole document, which it then saves in XAML format to a MemoryStream. It then converts that memory stream to a text string and applies a regular expression, which finds all instances of DEVX that don't already have
(tm) applied to them. Finally, it writes the modified XAML string back out to another MemoryStream, which is then loaded back into the RichTextBox.
Working with RichTextBox in C#
The RichTextBox control, like all of the other WPF controls, was primarily designed to be worked with in XAML. Despite this orientation it is both possible and useful to create a RichTextBox control in code. For example, using code is useful when you want to simplify configuring a RichTextBox control and a group of related toolbar buttons as a single component.
To create a component that groups controls you'll want to subclass one of the layout controls, such as a StackPanel, which will allow you to add the toolbar, buttons, and RichTextBox into your composite control. In the constructor, you'll need to build out the WPF components, adding controls as the toolbar, buttons, and RichTextBox but not the command interface. Unfortunately building out the Command interface in the constructor will result in buttons that do nothing. Despite my best research attempts I've been unable to find out why, but if I had to guess I would assume it has something to do with the control lifecycle.
The best solution I've been able to find to this issue is to add a
Loaded event handler in the constructor that then handles binding the buttons to the RichTextBox control. In the code snippet below, the Bold button in the toolbar gets initialized in the constructor and the code attaches an event handler to the
Loaded event. The
Loaded event sets up the command bindings by setting the
CommandTarget to point to the RichTextBox and the
Command to point to the
EditingCommands.ToggleBold enumeration.
ToggleButton bold;
public CustomRichTextBox()
{
//... Initialize the container, toolbar
bold = new ToggleButton();
this.Loaded += new RoutedEventHandler(
CompositeRichTextBox_Loaded);
//...Initialize the rest of the control
}
void CompositeRichTextBox_Loaded(
object sender, RoutedEventArgs e)
{
bold.CommandTarget = myRichTextBox;
bold.Command = EditingCommands.ToggleBold;
//... Initialize the other buttons
}
For further information on how to exploit the power of the RichTextBox control in WPF, I urge you to explore the
downloadable code examples included with this article. The examples cover both XAML and C# techniques for wiring together the RichTextBox.