Search code examples
c#wpf.net-4.5richtextbox

How to make some parts of a string to be bold and with different font style (size, font weight) within a WPF RichTextBox


I have below WPF RichTextBox which is bound to an MVVM property in my view model. The property SampleText contains a string, let's say, e.g.:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

I would like to make it visible in the RichTextBox in the following way:

enter image description here

As seen above, I would like to show all the paragraph using the same font (Segoe UI) but with some words highlighted in bold and the first phrase using a bigger font size.

Below my code:

<RichTextBox IsReadOnly="True"
             Focusable="False">
    <FlowDocument>
         <Paragraph>
               <Run Text="{Binding SampleText}" />
         </Paragraph>
    </FlowDocument>
</RichTextBox>

In case of bold, I have tried and inserted some <Bold> and </Bold> pair tags around some words and they are not displayed in the RichTextBox as bold, instead the <Bold> and </Bold> tags are not recognized and they are simply displayed as is in the RichTextBox.

In case of applying a bigger font size for first line, I don't have idea on how to do it, I don't know what is the correct tags pair to use.

How can I do this in WPF?

My SampleText property is dynamically changed programmatically from code, I mean, I assign it different formatted values (by formatted i mean, applying tags like and , etc.) depending on the scenario so it would be good an approach that would work simply by assigning the formatted value to that property and then it would be automatically processed and displayed correctly in the RichTextBox.


Solution

  • I'm gonna say at the outset I'm sure I got this by synthesizing one or more SO answers from a lifetime ago, but I have no idea whom to credit as this code is at least 7 years old.

    As I think you realized by now you can't actually just bind an RTF string to the RichTextBox (which, you know, would be too easy...), so instead I subclass and use a custom DP. You should easily be able to adapt this to your needs though.

        public class BindableRichTextBox : RichTextBox
        {
            #region string RichText dependency property
            public static readonly DependencyProperty RichTextProperty = 
                DependencyProperty.Register(
                    "RichText", 
                    typeof(string), 
                    typeof(BindableRichTextBox), 
                    new PropertyMetadata(
                        (string)null,
                        (obj, args) =>
                        {
                            ((BindableRichTextBox)obj).OnRichTextChanged(args);
                        }));
            public string RichText
            {
                get
                {
                    return (string)GetValue(RichTextProperty);
                }
                set
                {
                    SetValue(RichTextProperty, value);
                }
            }
            private void OnRichTextChanged(DependencyPropertyChangedEventArgs args)
            {
                string rtf = args.NewValue as string;
                if (string.IsNullOrEmpty(rtf))
                {
                    this.Document = null;
                    return;
                }
                this.Document = GetFlowDocumentFromRTF(rtf);
            }
            #endregion
    
            private FlowDocument GetFlowDocumentFromRTF(string text)
            {
                FlowDocument document = new FlowDocument();
    
                using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(text)))
                {                    
                    TextRange tr = new TextRange(document.ContentStart, document.ContentEnd);
                    tr.Load(ms, DataFormats.Rtf);
                }
                return document;
            }
        }
    

    To use this, you would then just say:

    <local:BindableRichTextBox IsReadOnly="True"
                               Focusable="False"
                               RichText="{Binding SampleText}"/>