So I am writing a small Twitter client for me to use. I am using a combination of one big panel, with smaller panels representing the individual tweets. In each smaller panel, I have a PictureBox and a RichTextBox.
Now, my problem is that loading more than 10 tweets causes a slowdown because I am dynamically generating the panels. So I decided to do this using a BackgroundWorker and then add those panels to the main panel.
I’ve done this numerous times with writing text to a textbox from a different thead(even wrote tutorials on it). Yet I cannot get this to work. I get the error message:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
Code:
List<Panel> panelList = new List<Panel>();
foreach (UserStatus friendStatus in list)
{
PictureBox pbTweet = new PictureBox();
// ...
// code to set numerous properties
// ...
RichTextBox rtbTweet = new RichTextBox();
// ...
// code to set numerous properties
// ...
Panel panelTweet = new Panel();
// ...
// code to set numerous properties
// ...
panelTweet.Controls.Add(pbTweet);
panelTweet.Controls.Add(rtbTweet);
panelList.Add(panelTweet);
}
if (panelMain.InvokeRequired)
panelMain.BeginInvoke((MethodInvoker)delegate { foreach (Panel p in panelList) { panelMain.Controls.Add(p); } });
Anybody notice any problems?
When using a background thread, you have to completely separate out the parts that retrieve data from the parts that modify the form controls. All code that modifies the form controls must be invoked on the UI thread, even if it will take some time to do. There is no way round this.
This is normally a good strategy is because, usually, getting the data into memory is the slow part and updating the UI is the fast part (relative to each other).
In your code example, all of the code is the UI-modification part, so it must all go in the UI thread.
EDIT: To optimise the UI part, you could experiment with calling
SuspendLayoutandResumeLayouton the panels that you are modifying.