1

Currently my application have a textbox that will show 500 lines of live logging on the screen. Since the application have alot of heavy task running behind, so i try to improve this part for my application as much as i can. Open for any suggestion. Thanks.

WPF:

<TextBox Text="{Binding StatusMessage}" TextWrapping="Wrap" AcceptsReturn="True" />

Method 1:

private void OutputMessage(string msg)
{
    //Result
    //1000  Lines     108ms
    //10000 Lines    1687ms
    if(!string.IsNullOrEmpty(msg))
    {
        string msgWithTimeStamp = System.DateTime.Now.ToString() + ": \t" + msg;

        int msgLine = 0;
        if (!string.IsNullOrEmpty(StatusMessage))
        {
            //Only show 500 lines of latest messages...
            msgLine = StatusMessage.Count(m => m == '\n');
            if (msgLine > 500)
                StatusMessage = StatusMessage.Remove(0, StatusMessage.IndexOf("\n") + 1);

            StatusMessage = StatusMessage + "\n" + msgWithTimeStamp;
        }
        else
            StatusMessage = msgWithTimeStamp;
    }
}

Method 2 (Better performance):

List<string> msgList;
private void OutputMessage(string msg)
{
    //Result
    //1000  Lines     31ms
    //10000 Lines    377ms
    if (!string.IsNullOrEmpty(msg))
    {
        string msgWithTimeStamp = System.DateTime.Now.ToString() + ": \t" + msg;
        msgList.Add(msgWithTimeStamp);

        if (msgList.Count > 500)
            msgList.RemoveAt(0);

        StatusMessage = String.Join("\n", msgList);
    }
}
1
  • 1
    I don't think this question is well suited for stackoverflow. Here we dealing with broken code, so, if your code is actually working, you may try to ask this question on another site Commented Jan 30, 2019 at 2:59

2 Answers 2

4

Instead of using a TextBox you could use an ItemsControl and data bind its ItemsSource to an ObservableCollection. Then you just append each new message to the ObservableCollection and the ItemsControl will automatically update to show the new entry at the end of its list.

Sign up to request clarification or add additional context in comments.

1 Comment

Definitely a good option, especially if used in conjunction with a VirtualizingStackPanel.
3

The biggest problem is the following line:

StatusMessage = String.Join("\n", msgList);

This means your rebuilding the entire string every time the main list of strings is updated, and it loops through the entire list, allocating new memory buffers until the buffer is large enough to fill the entire string (all 500 lines). When your message list grows to 500 lines, it means the next message will cause 500 buffer allocations just to rebuild the full string.

A better way would be to maintain a StringBuilder alongside your list of messages (in your msgList variable). StringBuilder is smart in how it allocates buffers as you modify your messages.

I wrote the following snippet, and on my machine the time it takes to add a new message to the list that already has 500 messages in it is less than a millisecond.

// Somewhere in your code, probably next to your [msgList] variable...
private StringBuilder sb = new StringBuilder();

private void OutputMessage(string msg)
{
    if (!string.IsNullOrEmpty(msg))
    {
        string msgWithTimeStamp = System.DateTime.Now.ToString() + ": \t" + msg;
        msgList.Add(msgWithTimeStamp);
        sb.AppendLine(msgWithTimeStamp);

        if (msgList.Count > 500)
        {
            sb.Remove(0, msgList[0].Length + 2); // The +2 is to account for the new line and carriage return characters.
            msgList.RemoveAt(0);
        }

        statusMessage = sb.ToString();
    }
}

The only downside to this approach is the maintenance of the same set of messages twice.

1 Comment

I think Join uses StringBuilder internally, but string builder has limited capacity and that capacity is expanded every time the limit is reached causing new memory allocations. so your approach avoids all those allocation's once it reaches 500 lines limit. +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.