Home > Net >  How to remove the top line of text from RichTextBox control in WPF?
How to remove the top line of text from RichTextBox control in WPF?

Time:09-11

I'm working on a WPF application, where I need a space to frequently display lines of colored text, in a console-like manner (new line displays at the bottom, the rest is moving up). I've decided to use a RichTextBox control named "outputBox" for that purpose:

<RichTextBox Name="outputBox" 
                         Grid.Row="0"
                         Background="Black"
                         Foreground="White"
                         Margin="10"
                         FontSize="14"
                         IsReadOnly ="True"
                         Focusable="False"
                         FontFamily="Consolas"
                         VerticalScrollBarVisibility="Visible"
                         >

I've also created the following method for appending new text lines (each of different color) to the outputBox:

private void PrintMessage(string msg, MessageType type = MessageType.Default)
        {

            TextRange tr = new(this.Window.outputBox.Document.ContentEnd, this.Window.outputBox.Document.ContentEnd);
            tr.Text = "\n"   msg;

            switch (type)
            {
                case (MessageType.Default):
                    tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.LightGray);
                    break;
                case (MessageType.UserInput):
                    tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Aqua);
                    break;
                case (MessageType.SystemFeedback):
                    tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.DarkSalmon);
                    break;
             }

            Window.outputBox.ScrollToEnd();
        }

The issue is, when the outputBox reaches enormous amount of text lines (e.g. 100 000), the application suffers significant performance drop. To remedy this, I want to set a limit of text lines on the outputBox, so when it reaches that limit, the very first top line is removed/cleared without losing text formatting of the remaining text lines. How to accomplish this?

CodePudding user response:

The code will have better performance if a text to the RichTextBox will be added to the Inlines collection of the Paragraph.

But to improve performance when shrinking a document to limit some amount of lines in it I would recommend to limit the paragraph size.

The code below implements this logic:

public static class RichTextBoxExt
{
    public static void PrintMessage(this RichTextBox rtb, string msg, MessageType type = MessageType.Default)
    {
        // Maximum of blocks in the document
        int MaxBlocks = 500; 
   
        // Maximum of lines in one block (paragraph)
        int InlinesPerBlock = 500;

        SolidColorBrush brush = Brushes.LightGray;
        switch (type)
        {
            case MessageType.UserInput:
                brush = Brushes.Aqua;
                break;
            case MessageType.SystemFeedback:
                brush = Brushes.DarkSalmon;
                break;
        }

        // Get the latest block in the document and try to append a new message to it
        if (rtb.Document.Blocks.LastBlock is Paragraph paragraph)
        {
            var nl = Environment.NewLine;

            // If the current block already contains the maximum count of lines create a new paragraph
            if (paragraph.Inlines.Count >= InlinesPerBlock)
            {
                nl = string.Empty;
                paragraph = new Paragraph();
                rtb.Document.Blocks.Add(paragraph);
            }                
            paragraph.Inlines.Add(new Run(nl   msg) { Foreground = brush });
        }

        if (rtb.Document.Blocks.Count >= MaxBlocks)
        {
            // When the number of lines more that (MaxBlocks-1)*InlinesPerBlock  remove the first block in the document
            rtb.Document.Blocks.Remove(rtb.Document.Blocks.FirstBlock);
        }
    }
}

And perhaps the paragraph Margin should be adjusted for better visual:

<RichTextBox x:Name="rtb" Margin="3"  VerticalScrollBarVisibility="Auto">
    <RichTextBox.Resources>
        <Style TargetType="{x:Type Paragraph}">
            <Setter Property="Margin" Value="2,0,0,2"/>
        </Style>
    </RichTextBox.Resources>
    <FlowDocument>
        <Paragraph>                    
        </Paragraph>
    </FlowDocument>
</RichTextBox>

And finally to add a message:

rtb.PrintMessage("Some_Message");
rtb.ScrollToEnd();
  • Related