Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Displaying HTML in a WPF RichTextBox

0.00/5 (No votes)
2 May 2016 1  
Presents code to display bindable HTML text in a WPF RichTextBox or a WebBrowser.

Introduction

I recently had need to display part of some bound read-only text with some of the text bolded. I could have used multiple controls, but that would reduce maintainability. I wanted to use HTML because that is well understood by many people, and it seemed like it would be useful in other situations.

The RichTextBox Design

I used a behavior to do this, but it could have been class derived from the RichTextBox.

public class HtmlRichTextBoxBehavior : DependencyObject
{
 public static readonly DependencyProperty TextProperty =
   DependencyProperty.RegisterAttached("Text", typeof(string),
   typeof(HtmlRichTextBoxBehavior), new UIPropertyMetadata(null, OnValueChanged));

 public static string GetText(RichTextBox o) { return (string)o.GetValue(TextProperty); }

 public static void SetText(RichTextBox o, string value) { o.SetValue(TextProperty, value); }

 private static void OnValueChanged(DependencyObject dependencyObject,
   DependencyPropertyChangedEventArgs e)
 {
  var richTextBox = (RichTextBox)dependencyObject;
  var text = (e.NewValue ?? string.Empty).ToString();
  var xaml = HtmlToXamlConverter.ConvertHtmlToXaml(text, true);
  var flowDocument = XamlReader.Parse(xaml) as FlowDocument;
  HyperlinksSubscriptions(flowDocument);
  richTextBox.Document = flowDocument;
 }

 private static void HyperlinksSubscriptions(FlowDocument flowDocument)
 {
  if (flowDocument == null) return;
  GetVisualChildren(flowDocument).OfType<Hyperlink>().ToList()
           .ForEach(i => i.RequestNavigate += HyperlinkNavigate);
 }

 private static IEnumerable<DependencyObject> GetVisualChildren(DependencyObject root)
 {
  foreach (var child in LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
  {
   yield return child;
   foreach (var descendants in GetVisualChildren(child)) yield return descendants;
  }
 }

 private static void HyperlinkNavigate(object sender,
  System.Windows.Navigation.RequestNavigateEventArgs e)
 {
  Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
  e.Handled = true;
 }
}

This code depends on code that is available from Microsoft; the HtmlToXamlConverter. All this Microsoft code is included in the folder HtmlConverter in the sample project.

Using the Behavior with a RichTextBox

The most straight forward way to use the behavior is as follows:

<RichTextBox Grid.Row="1"
             local:HtmlRichTextBoxBehavior.Text="{Binding Text}" />

You could have some unintended issues with this because you can still edit the RichTextBox. There are a few other issues also. To fix at least most of these issues I did the following:

<RichTextBox Background="Transparent"
             BorderThickness="0"
             behaviors:RichTextBoxHelper.Text="{Binding Name}"
             IsDocumentEnabled="True"
             IsReadOnly="True" />

This makes the RichTextBox look a lot more like a TextBox. The IsDocumentEnabled="True" is required to enable the hyperlinks. the IsReadOnly="True" ensures that the content cannot be changed. 

The WebBrowser Design

Used a behavior also for binding a string containing the HTML to the contents of a WebBrowser:

public class WebBrowserBehavior
{
 public static readonly DependencyProperty BodyProperty =
   DependencyProperty.RegisterAttached("Body", typeof(string), typeof(WebBrowserBehavior),
    new PropertyMetadata(OnChanged));

 public static string GetBody(DependencyObject dependencyObject)
 {
  return (string)dependencyObject.GetValue(BodyProperty);
 }

 public static void SetBody(DependencyObject dependencyObject, string body)
 {
  dependencyObject.SetValue(BodyProperty, body);
 }

 private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
  ((WebBrowser)d).NavigateToString((string)e.NewValue);
}

This is about a simple a behavior as can be created

Using the Behavior with a WebBrowser

The most straight forward way to use the behavior is as follows:

<WebBrowser local:WebBrowserBehavior.Body="{Binding Text}" />

Points of Interest

Right now the Hyperlinks do not work for the RichTextBox. Apparently this is an issue with the WPF RichTextBox. If something similar is done with the WinForm RichTextBox, "DetectUrls="True"" will enable Hyperlinks.

When a Hyperlink is clicked in the WebBrowser control, the URI is immediately opened. This may not be particularly desirable, so may want to disable it.

One of the advantages of using the RichTextBox is that the behavior can be updated to do a conversion back. Actually some of the key strokes work in the RichTextBox so that you can bold an entry with the "ctrl + b" keystrokes. I did not create the ability to convert back, but would be an easy task.

History

  • 05/02/2016: Initial version.
  • 05/03/2016: Added WebBrowser version to sample

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here