Binding to a RichTextBox in WPF

Published on 11 december 2017

I've been doing some WPF development the last couple of weeks, and one thing that bugged me was that there is no way (as far as I know) to bind content to a RichTextBox. This makes it kind of difficult to follow the MVVM pattern since the view model needs intimate knowledge of the view.

In my case, I wanted to bind the textbox against a resource using a pack:// URI, so I threw together some code to do this. I am far from an expert on WPF, so if you have any suggestions then please let me know!

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace MyApp.Controls
{
    public sealed class BindableRichTextBox : RichTextBox
    {
        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source",
                typeof(Uri), typeof(BindableRichTextBox),
                new PropertyMetadata(OnSourceChanged));

        public Uri Source
        {
            get => GetValue(SourceProperty) as Uri;
            set => SetValue(SourceProperty, value);
        }

        private static void OnSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is BindableRichTextBox rtf && rtf.Source != null)
            {
                var stream = Application.GetResourceStream(rtf.Source);
                if (stream != null)
                {
                    var range = new TextRange(rtf.Document.ContentStart, rtf.Document.ContentEnd);
                    range.Load(stream.Stream, DataFormats.Rtf);
                }
            }
        }
    }
}

You can now use a binding as you normally would in your XAML (or simply set it directly).

<Window x:Class="MyApp.MyView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ui="clr-namespace:MyApp.Controls"
        mc:Ignorable="d">
    <StackPanel>
        <ui:BindableRichTextBox Source="{Binding Licenses}" />
        <ui:BindableRichTextBox Source="pack://application:,,,/MyApp;component/MyApp/Resources/Document.rtf" />
    </StackPanel>
</Window>