I have a .NET 4.5 WinForm program that queries a text-based database using ODBC. I then want to display every result in a multiline textbox and I want to do it in the quickest way possible.
The GUI does not have to be usable during the time the textbox is being updated/populated. However, it'd be nice if I could update a progress bar to let the user know that something is happening - I believe a background worker or new thread/task is necessary for this but I've never implemented one.
I initially went with this code and it was slow, as it drew out the result every line before continuing to the next one.
OdbcDataReader dbReader = com.ExecuteReader();
while (dbReader.Read())
{
txtDatabaseResults.AppendText(dbReader[0].ToString());
}
This was significantly faster.
string resultString = "";
while (dbReader.Read())
{
resultString += dbReader[0].ToString();
}
txtDatabaseResults.Text = resultString;
But there is a generous wait time before the textbox comes to life so I want to know if the operation can be even faster. Right now I'm fetching about 7,000 lines from the file and I don't think it's necessary to switch to AvalonEdit (correct me if my way of thinking is wrong, but I would like to keep it simple and use the built-in textbox).
You can make this far faster by using a
StringBuilder
instead of using string concatenation.Using
string
and concatenation creates a lot of pressure on the GC, especially if you're appending 7000 lines of text. Each time you usestring +=
, the CLR creates a new string instance, which means the older one (which is progressively larger and larger) needs to be garbage collected.StringBuilder
avoids that issue.Note that there will still be a delay when you assign the text to the
TextBox
, as it needs to refresh and display that text. TheTextBox
control isn't optimized for that amount of text, so that may be a bottleneck.As for pushing this into a background thread - since you're using .NET 4.5, you could use the new async support to handle this. This would work via marking the method containing this code as
async
, and using code such as:Despite the fact that a parallel
Thread
is recommended, the way you extract the lines from file is somehow flawed. Whilestring
is immutable everytime you concatenateresulString
you actually create another (bigger) string. Here,StringBuilder
comes in very useful:I am filling a regular TextBox (multiline=true) in a single call with a very long string (more than 200kB, loaded from a file. I just assign the Text property of TextBox with my string). It's very slow (> 1 second). The Textbox does anything else than display the huge string.
I used a very simple trick to improve performances : I replaced the multiline textbox by a RichTextBox (native control).
Now same loadings are instantaneous and RichTextBox has exactly the same appearance and behavior as TextBox with raw text (as long as you didn't tweaked it). The most obvious difference is RTB does not have Context menu by default.
Of course, it's not a solution in every case, and it's not aiming the OP question but for me it works perfectly, so I hope it could help other peoples facing same problems with Textbox and performance with big strings.
Use a StringBuilder: