Here are the steps to create a Rich Text Editor using WPF:
Software Requirements:
- .NET Framework 3.5 or higher
- Visual studio 2010 or higher
Control Requirements:
- One Rich Textbox
- Ribbon Controls to add menu like Microsoft Word
- Open Visual Studio and create a new WPF application with C# code as shown below,

- Download and add RibbonControlsLibrary reference and other existing References as shown below,
• Right click on References and goto Add Reference, Assemblies, then Framework and add two references from this:
a. System.Drawing
b. System.Windows.Forms
• Add downloaded Reference from Add Reference, Browse, then RibbonControlsLibrary.dll file and click Ok (if you downloaded from NuGet packages from VS then it will be added automatically to your project, so no need to browse this reference),
a. Figure is showing the example for adding references.
- Now the time for the design as shown below,
• Add required image files
• Add controls to the window in VS
a. Add Ribbon control and Rich textbox
b. To add Ribbon control add xaml class code in the beginning of window XAML code as
xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
Xaml Source- <Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon" Title="Editor" Width="1024" Height="700" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
- <Grid>
- <Frame Background="White" />
- <my:Ribbon Name="_ribbon" Margin="0,1,0,361">
- <my:Ribbon.ApplicationMenu>
- <my:RibbonApplicationMenu Visibility="Collapsed">
- </my:RibbonApplicationMenu>
- </my:Ribbon.ApplicationMenu>
- <my:RibbonTab Header="Home">
- <my:RibbonGroup Header="Edit">
- <my:RibbonButton x:Name="_btnPaste" Label="Paste" LargeImageSource="/Images/Paste32.png" ToolTip="Paste" Command="{x:StaticApplicationCommands.Paste}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Large" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_btnCut" Label="Cut" SmallImageSource="/Images/Cut16.png" ToolTip="Cut" Command="{x:StaticApplicationCommands.Cut}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_btnCopy" Label="Copy" SmallImageSource="/Images/Copy16.png" ToolTip="Copy" Command="{x:StaticApplicationCommands.Copy}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_btnClear" Label="Clear" SmallImageSource="/Images/Delete16.png" ToolTip="Clear" Command="{x:StaticEditingCommands.Delete}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_btnUndo" Label="Undo" SmallImageSource="/Images/Undo16.png " ToolTip="Undo" Command="{x:StaticApplicationCommands.Undo}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_bntRedo" Label="Redo" SmallImageSource="/Images/Redo16.png" ToolTip="Redo" Command="{x:StaticApplicationCommands.Redo}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButton x:Name="_btnSelectAll" Label="Select All" ToolTip="Select All" Command="{x:StaticApplicationCommands.SelectAll}" CommandTarget="{Binding ElementName=_richTextBox}" />
- </my:RibbonGroup>
- <my:RibbonGroup Header="Font">
- <my:RibbonControlGroup>
- <ComboBox x:Name="_fontFamily" IsEditable="True" Width="110" ToolTip="Font" SelectionChanged="FontFamily_SelectionChanged" />
- <ComboBox x:Name="_fontSize" IsEditable="True" Width="45" ToolTip="FontSize" SelectionChanged="FontSize_SelectionChanged" />
- </my:RibbonControlGroup>
- <my:RibbonControlGroup>
- <my:RibbonToggleButton x:Name="_btnBold" ToolTip="Bold" SmallImageSource="/Images/Bold16.png" Command="{x:StaticEditingCommands.ToggleBold}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonToggleButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonToggleButton.ControlSizeDefinition>
- </my:RibbonToggleButton>
- <my:RibbonToggleButton x:Name="_btnItalic" SmallImageSource="/Images/Italic16.png" ToolTip="Italic" Command="{x:StaticEditingCommands.ToggleItalic}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonToggleButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonToggleButton.ControlSizeDefinition>
- </my:RibbonToggleButton>
- <my:RibbonToggleButton x:Name="_btnUnderline" SmallImageSource="/Images/Underline16.png" ToolTip="Underline" Command="{x:StaticEditingCommands.ToggleUnderline}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonToggleButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonToggleButton.ControlSizeDefinition>
- </my:RibbonToggleButton>
- </my:RibbonControlGroup>
- </my:RibbonGroup>
- <my:RibbonGroup Header="Paragraph">
- <my:RibbonControlGroup>
- <my:RibbonRadioButton x:Name="_btnAlignLeft" Label="" SmallImageSource="/Images/LeftAlign16.png" ToolTip="Align Text Left" Command="{x:StaticEditingCommands.AlignLeft}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonRadioButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" /></my:RibbonRadioButton.ControlSizeDefinition>
- </my:RibbonRadioButton>
- <my:RibbonRadioButton x:Name="_btnAlignCenter" Label="" SmallImageSource="/Images/CenterAlign16.png" ToolTip="Center" Command="{x:StaticEditingCommands.AlignCenter}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonRadioButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonRadioButton.ControlSizeDefinition>
- </my:RibbonRadioButton>
- <my:RibbonRadioButton x:Name="_btnAlignRight" Label="" SmallImageSource="/Images/RightAlign16.png" ToolTip="Align Text Right" Command="{x:StaticEditingCommands.AlignRight}" CommandTarget="{Binding ElementName=_richTextBox}" />
- <my:RibbonRadioButton x:Name="_btnAlignJustify" Label="" SmallImageSource="/Images/JustifyAlign16.png" ToolTip="Justify" Command="{x:StaticEditingCommands.AlignJustify}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonRadioButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonRadioButton.ControlSizeDefinition>
- </my:RibbonRadioButton>
- </my:RibbonControlGroup>
- <my:RibbonControlGroup>
- <my:RibbonRadioButton x:Name="_btnBullets" Label="" mallImageSource="/Images/Bullets16.png" ToolTip="Bullets" Command="{x:StaticEditingCommands.ToggleBullets}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonRadioButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonRadioButton.ControlSizeDefinition>
- </my:RibbonRadioButton>
- <my:RibbonRadioButton x:Name="_btnNumbers" Label="" SmallImageSource="/Images/Numbering16.png" ToolTip="Numbering" Command="{x:StaticEditingCommands.ToggleNumbering}" CommandTarget="{Binding ElementName=_richTextBox}">
- <my:RibbonRadioButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Small" IsLabelVisible="False" />
- </my:RibbonRadioButton.ControlSizeDefinition>
- </my:RibbonRadioButton>
- </my:RibbonControlGroup>
- </my:RibbonGroup>
- <my:RibbonGroup Header="Image">
- <my:RibbonButton Width="53" Height="39" LargeImageSource="/Images/Images.png" ToolTip="Insert Image" Click="btn_importimg_Click" Margin="5,15,5,5">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Large" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- </my:RibbonGroup>
- <my:RibbonGroup Header="Font Color">
- <my:RibbonButton Width="53" Height="Auto" LargeImageSource="/Images/font_color.png" ToolTip="Change font color" Click="btn_Font_Click" Margin="5,20,5,5">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Large" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- </my:RibbonGroup>
- <my:RibbonGroup Header="File">
- <my:RibbonButtonLargeImageSource="/Images/Open.png" ToolTip="Open Document File(.doc)" Click="btn_OpenDoc_Click" Margin="5,20,5,5" Height="38" Width="54">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Large" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- <my:RibbonButtonLargeImageSource="/Images/Save.ico" ToolTip="Save As Doc" Click="btn_SaveDoc_Click" Margin="5,20,5,5" Height="41">
- <my:RibbonButton.ControlSizeDefinition>
- <my:RibbonControlSizeDefinitionImageSize="Large" />
- </my:RibbonButton.ControlSizeDefinition>
- </my:RibbonButton>
- </my:RibbonGroup>
- </my:RibbonTab>
- </my:Ribbon>
- <RichTextBoxAcceptsTab="True" VerticalScrollBarVisibility="Auto" TabIndex="3" SpellCheck.IsEnabled="True" Margin="0,138,0,0" x:Name="Workspace" BorderBrush="Black" BorderThickness="0.7,0.7,0.7,0.7" Height="532" VerticalAlignment="Top" SelectionChanged="Workspace_SelectionChanged" />
- </Grid>
- </Window>
- Now is the time to add some functionality to this editor. To do that click F7 or go to C# code and write as given below,
• Import some references to it as below,• To add fonts and font size after page initializes write code in MainWindow() as below,- using System.Windows.Navigation;
- using System.Windows.Controls.Primitives;
- using System.IO;
- using Microsoft.Win32;
• Selection change event as below,- public MainWindow()
- {
- InitializeComponent();
- _fontFamily.ItemsSource = System.Windows.Media.Fonts.SystemFontFamilies;
- _fontSize.ItemsSource = FontSizes;
- }
- public double[] FontSizes
- {
- get
- {
- return new double[] { 3.0, 4.0, 5.0, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5,13.0,13.5,14.0, 15.0,16.0, 17.0, 18.0, 19.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0,32.0, 34.0, 36.0, 38.0, 40.0, 44.0, 48.0, 52.0, 56.0, 60.0, 64.0, 68.0, 72.0, 76.0,80.0, 88.0, 96.0, 104.0, 112.0, 120.0, 128.0, 136.0, 144.0
- };
- }
- }
• Add other functionalities during selection change event of RichText box as given below,- void ApplyPropertyValueToSelectedText(DependencyPropertyformattingProperty, object value)
- {
- if (value == null)
- return;
- Workspace.Selection.ApplyPropertyValue(formattingProperty, value);
- }
- private void FontFamily_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- try
- {
- FontFamilyeditValue = (FontFamily) e.AddedItems[0];
- ApplyPropertyValueToSelectedText(TextElement.FontFamilyProperty, editValue);
- } catch (Exception) {}
- }
- private void FontSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- try
- {
- ApplyPropertyValueToSelectedText(TextElement.FontSizeProperty, e.AddedItems[0]);
- } catch (Exception) {}
- }
• Add function for inserting image and for font color selection,- void UpdateItemCheckedState(ToggleButton button, DependencyPropertyformattingProperty, object expectedValue)
- {
- object currentValue = Workspace.Selection.GetPropertyValue(formattingProperty);
- button.IsChecked = (currentValue == DependencyProperty.UnsetValue) ? false : currentValue != null && currentValue.Equals(expectedValue);
- }
- private void UpdateToggleButtonState()
- {
- UpdateItemCheckedState(_btnBold, TextElement.FontWeightProperty, FontWeights.Bold);
- UpdateItemCheckedState(_btnItalic, TextElement.FontStyleProperty, FontStyles.Italic);
- UpdateItemCheckedState(_btnUnderline, Inline.TextDecorationsProperty, TextDecorations.Underline);
- UpdateItemCheckedState(_btnAlignLeft, Paragraph.TextAlignmentProperty, TextAlignment.Left);
- UpdateItemCheckedState(_btnAlignCenter, Paragraph.TextAlignmentProperty, TextAlignment.Center);
- UpdateItemCheckedState(_btnAlignRight, Paragraph.TextAlignmentProperty, TextAlignment.Right);
- UpdateItemCheckedState(_btnAlignJustify, Paragraph.TextAlignmentProperty, TextAlignment.Right);
- }
- private void UpdateSelectionListType()
- {
- Paragraph startParagraph = Workspace.Selection.Start.Paragraph;
- Paragraph endParagraph = Workspace.Selection.End.Paragraph;
- if (startParagraph != null && endParagraph != null && (startParagraph.Parent is ListItem) && (endParagraph.Parent is ListItem) && object.ReferenceEquals(((ListItem) startParagraph.Parent).List, ((ListItem) endParagraph.Parent).List)) {
- TextMarkerStylemarkerStyle = ((ListItem) startParagraph.Parent).List.MarkerStyle;
- if (markerStyle == TextMarkerStyle.Disc) //bullets
- {
- _btnBullets.IsChecked = true;
- } else if (markerStyle == TextMarkerStyle.Decimal) //number
- {
- _btnNumbers.IsChecked = true;
- }
- } else {
- _btnBullets.IsChecked = false;
- _btnNumbers.IsChecked = false;
- }
- }
- private void UpdateSelectedFontFamily()
- {
- object value = Workspace.Selection.GetPropertyValue(TextElement.FontFamilyProperty);
- FontFamilycurrentFontFamily = (FontFamily)((value == DependencyProperty.UnsetValue) ? null : value);
- if (currentFontFamily != null)
- {
- _fontFamily.SelectedItem = currentFontFamily;
- }
- }
- private void UpdateSelectedFontSize()
- {
- object value = Workspace.Selection.GetPropertyValue(TextElement.FontSizeProperty);
- _fontSize.SelectedValue = (value == DependencyProperty.UnsetValue) ? null : value;
- }
- private void UpdateVisualState()
- {
- UpdateToggleButtonState();
- UpdateSelectionListType();
- UpdateSelectedFontFamily();
- UpdateSelectedFontSize();
- }
- private void Workspace_SelectionChanged(object sender, RoutedEventArgs e) {
- UpdateVisualState();
- }
For image insertionFor Font color change- public void selectImg(RichTextBoxrc)
- {
- OpenFileDialogdlg = new OpenFileDialog();
- dlg.Filter = "Image files (*.jpg, *.jpeg,*.gif, *.png) | *.jpg; *.jpeg; *.gif; *.png";
- var result = dlg.ShowDialog();
- if (result.Value)
- {
- Uri uri = new Uri(dlg.FileName, UriKind.Relative);
- BitmapImagebitmapImg = new BitmapImage(uri);
- Image image = new Image();
- image.Stretch = Stretch.Fill;
- image.Width = 250;
- image.Height = 200;
- image.Source = bitmapImg;
- vartp = rc.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
- new InlineUIContainer(image, tp);
- }
- }
- private void btn_importimg_Click(object sender, RoutedEventArgs e)
- {
- selectImg(Workspace);
- }
• Write the code for saving as Doc File and open Doc file,- private void fontcolor(RichTextBoxrc)
- {
- var colorDialog = new System.Windows.Forms.ColorDialog();
- if (colorDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- {
- var wpfcolor = Color.FromArgb(colorDialog.Color.A, colorDialog.Color.R, colorDialog.Color.G, colorDialog.Color.B);
- TextRange range = new TextRange(rc.Selection.Start, rc.Selection.End);
- range.ApplyPropertyValue(FlowDocument.ForegroundProperty, new SolidColorBrush(wpfcolor));
- }
- }
- private void btn_Font_Click(object sender, RoutedEventArgs e)
- {
- fontcolor(Workspace);
- }
To saveTo open- private void btn_SaveDoc_Click(object sender, RoutedEventArgs e)
- {
- SaveFileDialogsavefile = new SaveFileDialog();
- // set a default file name
- savefile.FileName = "unknown.doc";
- // set filters - this can be done in properties as well
- savefile.Filter = "Document files (*.doc)|*.doc";
- if (savefile.ShowDialog() == true)
- {
- TextRange t = new TextRange(Workspace.Document.ContentStart, Workspace.Document.ContentEnd);
- FileStream file = new FileStream(savefile.FileName, FileMode.Create);
- t.Save(file, System.Windows.DataFormats.Rtf);
- file.Close();
- }
- }
- private void btn_OpenDoc_Click(object sender, RoutedEventArgs e)
- {
- OpenFileDialogdlg = new OpenFileDialog();
- dlg.Filter = "Document files (*.doc)|*.doc";
- var result = dlg.ShowDialog();
- if (result.Value)
- {
- TextRange t = new TextRange(Workspace.Document.ContentStart, Workspace.Document.ContentEnd);
- FileStream file = new FileStream(dlg.FileName, FileMode.Open);
- t.Load(file, System.Windows.DataFormats.Rtf);
- }
- }
Read more articles on WPF:

Alvin ChesaroPosted Sep 22, 2018, 4:22 AM
This is the best wysiwyg editor I have managed to find. Great job on this!
Aram NasserPosted Jul 16, 2018, 9:53 AM
Thanks for this interesting article. However, although I declared the System.Windows.Controls.Ribbon.Ribbon library, I am still having problems. The my:Ribbon..... is not defined, as well as all the declarations related to (my). Could you, please, help me with this?
Rafnas T PPosted Jun 30, 2016, 6:43 AM
Add name space using System.Windows;
Xavier BarrullPosted Jun 27, 2016, 1:27 PM
Hi, I have an error when I write void ApplyPropertyValueToSelectedText(DependencyPropertyformattingProperty, object value) { if (value == null) return; Workspace.Selection.ApplyPropertyValue(formattingProperty, value); } What the reason about this? The error is about DepencyPropertyformattingProperty is The name of the type or namespace could not be found (are you missing a using directive or an assembly reference?)
Sonu ChaudharyPosted Jun 7, 2016, 12:43 PM
good one
Rafnas T PPosted Mar 16, 2016, 6:54 AM
Thank you all.
Kashif SohailPosted Mar 15, 2016, 5:26 PM
Good article,
Debasis SahaPosted Mar 15, 2016, 1:49 PM
Good One..
Saillesh PawarPosted Mar 15, 2016, 8:41 AM
Nice Share
Mohammed IbrahimPosted Mar 15, 2016, 6:07 AM
nice
Debasis SahaPosted Mar 15, 2016, 12:40 AM
Nice one..
Vignesh ManiPosted Mar 14, 2016, 5:44 PM
Nice