Click here to Skip to main content
13,254,236 members (63,118 online)
Click here to Skip to main content
Add your own
alternative version


60 bookmarked
Posted 5 Jan 2010

WPF RichTextEditor with Toolbar

, 5 Jan 2010
Rate this:
Please Sign up or sign in to vote.
WPF RichTextBox with standard Text-formatting possiblities


While playing around with WPF, I got stuck with the RichTextBox and their possibilities in comparison to the RichTextBox in WinFoms.
So I tried to develop a UserControl with the basic text-formatting functions in WPF.
This article is it.

I want to point out that I did use the Color Picker from Sacha Barber's article:

The Icons are from:

Using the Code

So, how does it all work. It is rather simple, my RTF-Editor is a WPF UserControl-Project.
It can easily be used like I demonstrated it in my TestApplication whose XAML looks like this:

<Window x:Class="TestApp.Window1"




    Title="Window1" Height="300" Width="300">

The RTFBox class is my RTF-Editor.
The UserInterface consists of a RichTextBox, a StatusBar and two ToolBars which hold all the buttons for text-formatting.

The first toolbars XAML looks like this:

  <ToolBar x:Name="ToolBarOben" DockPanel.Dock="Top">
    <Button x:Name="ToolStripButtonOpen" 

    <Image Source="Images\Open.png" Stretch="None"/>
<Button x:Name="ToolStripButtonPrint" 

    <Image Source="Images\Print.png" Stretch="None"/>    
<Button x:Name="ToolStripButtonCut" 

                        Command="ApplicationCommands.Cut" ToolTip="Cut">
    <Image Source="Images\Cut.png" Stretch="None"/>
<Button x:Name="ToolStripButtonCopy" 

                        Command="ApplicationCommands.Copy" ToolTip="Copy">
    <Image Source="Images\Copy.png" Stretch="None"/>    
<Button x:Name="ToolStripButtonPaste" 

                        Command="ApplicationCommands.Paste" ToolTip="Paste">
    <Image Source="Images\Paste.png" Stretch="None"/>    
<Button x:Name="ToolStripButtonUndo" 

                        Command="ApplicationCommands.Undo" ToolTip="Undo">
    <Image Source="Images\Undo.png" Stretch="None"/>    
<Button x:Name="ToolStripButtonRedo" 

                        Command="ApplicationCommands.Redo" ToolTip="Redo">
    <Image Source="Images\Redo.png" Stretch="None"/>    
<ComboBox x:Name="Fonttype" ItemsSource="{Binding Mode=OneWay, 
                                             Source={StaticResource FontListKlasse}}" 

                          DropDownClosed="Fonttype_DropDownClosed" />
        <ComboBox x:Name="Fontheight" ItemsSource="{Binding Mode=OneWay, 
                                             Source={StaticResource FontHeightKlasse}}"  

                          DropDownClosed="Fontheight_DropDownClosed" />

As you can see, it is really straightforward. I used the ApplicationCommands for Cut, Copy, Paste, Undo, Redo and defined the necessary Handler for Open, Print.
A bit more complex are the ComboBoxes for FontType and FontHeight. I used a OneWay Binding to static resources that I defined in my XAML like this:

        <ObjectDataProvider x:Key="FontListKlasse" d:IsDataSource="True" 

                            ObjectType="{x:Type RTFEditor:FontList}"/>
        <ObjectDataProvider x:Key="FontHeightKlasse" d:IsDataSource="True" 

                            ObjectType="{x:Type RTFEditor:FontHeight}"/>

Here are the two classes FontHeight and FontList that hold the information.

class FontList : ObservableCollection<string> 
        public FontList() 
            foreach (FontFamily f in Fonts.SystemFontFamilies)
class FontHeight : ObservableCollection<string>
        public FontHeight()

The second ToolBar is similar so without pasting the full XAML code:
I used ToggleButtons for the textstyle (bold, italic, ...) and textalignment(right, left, ...).
If possible, I used EditingCommands like this:

<ToggleButton x:Name="ToolStripButtonBold" 


              <Image Source="Images\Bold.png" Stretch="None"/>                

There is no EditingCommand for strikethrough formatting, so I did this via TextDecorations:

private void ToolStripButtonStrikeout_Click(object sender, 
                                            System.Windows.RoutedEventArgs e)
            TextRange range = new TextRange(RichTextControl.Selection.Start, 

            TextDecorationCollection tdc = 
            if (tdc == null || !tdc.Equals(TextDecorations.Strikethrough))
                tdc = TextDecorations.Strikethrough;
                tdc = new TextDecorationCollection();
            range.ApplyPropertyValue(Inline.TextDecorationsProperty, tdc);

As there is no ColorDialog in WPF like the one in WinForms, I used one from Sacha Barber for Textforecolor and Textbackgroundcolor.

private void ToolStripButtonTextcolor_Click
			(object sender, RoutedEventArgs e)
            ColorDialog colorDialog = new ColorDialog();
            //colorDialog.Owner = this;
            if ((bool)colorDialog.ShowDialog())
                TextRange range = new TextRange(RichTextControl.Selection.Start, 

                    new SolidColorBrush(colorDialog.SelectedColor));      

For superscript and subscript exist EditingCommands but they do only work for OpenType Fonts. So instead of using them, I changed BaselineAlignments to display sub/superscript for all fonts like this:

private void ToolStripButtonSubscript_Click(object sender, RoutedEventArgs e)
            var currentAlignment = 

            BaselineAlignment newAlignment = 
              ((BaselineAlignment)currentAlignment == 
				BaselineAlignment.Subscript) ? 
                                 BaselineAlignment.Baseline : 

I added a Statusbar for displaying the line and columnnumber and a zoom function. The XAML is straightforward.

To get the line number, I had to start from the beginning and count all lines to the current cursor position like this:

private int LineNumber()
            TextPointer caretLineStart = 
            TextPointer p = RichTextControl.Document.ContentStart.GetLineStartPosition(0);
            int currentLineNumber = 1;
            while (true)
                if (caretLineStart.CompareTo(p) < 0)
                int result;
                p = p.GetLineStartPosition(1, out result);
                if (result == 0)
            return currentLineNumber;

To get the column number, I could use the GetOffsetToPosition function like this:

private int ColumnNumber()
            TextPointer caretPos = RichTextControl.CaretPosition;
            TextPointer p = RichTextControl.CaretPosition.GetLineStartPosition(0);
            int currentColumnNumber = Math.Max(p.GetOffsetToPosition(caretPos) - 1, 0);

            return currentColumnNumber;

At this point I realized that the WinForms RichTextBox offers a zoom function, the WPF RichTextBox doesn't. I did not find a way to implement one. (Any help in this regard will be appreciated.)

After I finished with the mentioned basic Texteditor functions, I wanted a possibility to get the RTF-content out of the RichTextControl, means the text with the rich text formatting. The WPF RichTextBox holds no straightforward way to get this so I did this:

public string GetRTF()
            TextRange range = new TextRange(RichTextControl.Document.ContentStart, 

            // Exception abfangen für StreamReader und MemoryStream
                using (MemoryStream rtfMemoryStream = new MemoryStream())
                    using (StreamWriter rtfStreamWriter = 
                                             new StreamWriter(rtfMemoryStream))
                        range.Save(rtfMemoryStream, DataFormats.Rtf);

                        rtfMemoryStream.Position = 0;
                        StreamReader sr = new StreamReader(rtfMemoryStream);
                        return sr.ReadToEnd();
            catch (Exception)

And the other direction looks like this:

public void SetRTF(string rtf)
            TextRange range = new TextRange(RichTextControl.Document.ContentStart, 
                using (MemoryStream rtfMemoryStream = new MemoryStream())
                    using (StreamWriter rtfStreamWriter = 
                                                   new StreamWriter(rtfMemoryStream))
                        rtfMemoryStream.Seek(0, SeekOrigin.Begin);

                        range.Load(rtfMemoryStream, DataFormats.Rtf);
            catch (Exception)

Your Opinion

I'm very interested in your opinion about the article and the code. Please leave some comments and let me know if the article could help you in any way.


  • 5th January, 2010: Initial post 


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Germany Germany
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionWould you like an About Box credit? Pin
Member 1032625625-Sep-17 2:37
memberMember 1032625625-Sep-17 2:37 
GeneralMy vote of 3 Pin
raiserle17-Jul-17 5:31
memberraiserle17-Jul-17 5:31 
QuestionUse DLL in vb .NET Project Pin
trC_9-Jun-17 14:32
membertrC_9-Jun-17 14:32 
QuestionSet RTF content through MemoryStream Pin
00zhang18-Apr-16 14:49
member00zhang18-Apr-16 14:49 
QuestionThanks You, Great Job Pin
Henka.Programmer7-Mar-16 1:40
memberHenka.Programmer7-Mar-16 1:40 
QuestionFormating disappears in the beginning Pin
Jesper Gissel5-Aug-14 3:42
memberJesper Gissel5-Aug-14 3:42 
QuestionI have great difficulty to activate GregorPross' otherwise praised "WPF RichTextEditor with Toolbar" software Pin
Member 995312118-Jun-13 17:45
memberMember 995312118-Jun-13 17:45 
AnswerRe: I have great difficulty to activate GregorPross' otherwise praised "WPF RichTextEditor with Toolbar" software Pin
Member 995312121-Jun-13 4:36
memberMember 995312121-Jun-13 4:36 
AnswerRe: I have great difficulty to activate GregorPross' otherwise praised "WPF RichTextEditor with Toolbar" software Pin
Member 995312121-Jun-13 17:28
memberMember 995312121-Jun-13 17:28 
SuggestionGreat, I'm using it Pin
Jetteroh13-Jun-12 4:11
memberJetteroh13-Jun-12 4:11 
I changed the counting of Rows and Columns, because it counted in a strange way.
Here is:
private int LineNumber()
    TextPointer caretLineStart = RichTextControl.CaretPosition.GetLineStartPosition(0);
    int currentLineNumber = 0;
    // Counts how many line starts before
    while (caretLineStart.GetLineStartPosition(currentLineNumber)!=null)
    return currentLineNumber * -1;
private int ColumnNumber()
    TextRange szov = new TextRange(RichTextControl.CaretPosition.GetLineStartPosition(0), RichTextControl.CaretPosition);
    // Counting in readable characters
    return szov.Text.Length;

modified 13-Jun-12 9:53am.

GeneralZoom functionality Pin
Le Duc Anh13-Feb-11 21:21
memberLe Duc Anh13-Feb-11 21:21 
GeneralMy vote of 5 Pin
E$w@r22-Jan-11 3:18
memberE$w@r22-Jan-11 3:18 
QuestionFind / Replace Functionality(text with sub or super script also) Pin
E$w@r22-Jan-11 3:17
memberE$w@r22-Jan-11 3:17 
GeneralMy vote of 5 Pin
Member 287883929-Sep-10 6:46
memberMember 287883929-Sep-10 6:46 
GeneralBold / Italics toolbar buttons Pin
Wjousts26-Jul-10 11:07
memberWjousts26-Jul-10 11:07 
QuestionSubscripted/superscripted characters lost from a saved rtf. Pin
VishalvPatil27-Jun-10 23:57
memberVishalvPatil27-Jun-10 23:57 
AnswerRe: Subscripted/superscripted characters lost from a saved rtf. Pin
ketansnadar30-Aug-12 3:12
memberketansnadar30-Aug-12 3:12 
GeneralThanks Pin
mpggcobol4-Jun-10 22:47
membermpggcobol4-Jun-10 22:47 
GeneralBinding Pin
Wizard_Memfis3-Jun-10 10:22
memberWizard_Memfis3-Jun-10 10:22 
GeneralNifty... Pin
TheArchitectmc5-Jan-10 4:23
memberTheArchitectmc5-Jan-10 4:23 
GeneralRe: Nifty... Pin
GregorPross6-Jan-10 2:52
memberGregorPross6-Jan-10 2:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.171114.1 | Last Updated 5 Jan 2010
Article Copyright 2010 by GregorPross
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid