3

What I have going on is a listview being dynamically created from a previous button click. Then ti starts a background worker in which should clear out the listview and populate the iistview with new information every 30 seconds.
I continously get: Cross-thread operation not valid: Control 'listView2' accessed from a thread other than the thread it was created on.

  private void watcherprocess1Updatelist()
    {
        listView2.Items.Clear();
        string betaFilePath1 = @"C:\Alpha\watch1\watch1config.txt";
        using (FileStream fs = new FileStream(betaFilePath1, FileMode.Open))
        using (StreamReader rdr = new StreamReader((fs)))
        {
            while (!rdr.EndOfStream)
            {
                string[] betaFileLine = rdr.ReadLine().Split(',');
                using (WebClient webClient = new WebClient())
                {
                    string urlstatelevel = betaFileLine[0];
                    string html = webClient.DownloadString(urlstatelevel);
                    File.AppendAllText(@"C:\Alpha\watch1\specificconfig.txt", html);
                }
            }
        }

3 Answers3

6

You cannot access your ListView from the background thread. You need to do this on the UI thread.

There are two options - first, you can switch this around to use a Windows.Forms.Timer to fire every 30 seconds. This will occur on the UI thread, which will avoid this problem entirely, but move the processing onto the UI thread. If your processing is slow, this could cause "hangs".

Alternatively, use Control.Invoke to marshal the calls to ListView back onto the UI thread:

 listView2.Invoke(new Action( () => listView2.Items.Clear() ) );

In any case, I'd rethink using a BackgroundWorker. It's not intended for "timed events" that happen on regular intervals. You should consider changing to a Windows.Forms.Timer (UI thread) if there will be no long processing, or a System.Timers.Timer (runs on a background thread) if the processing will take a while. This is a better design option than a BackgroundWorker which never terminates.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • you don't actually need the "new Action(...)", just the lambda is enough. – Stormenet Apr 05 '10 at 17:53
  • @Stormenet: Check this out: http://stackoverflow.com/questions/411579/why-must-a-lambda-expression-be-cast-when-supplied-as-a-plain-delegate-parameter – Reed Copsey Apr 05 '10 at 17:57
2

You need to use Control.Invoke to call code on the UI thread to update the listView.

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
2

Here's a pattern I use for methods that will mess with a UI control

public void DoSomethingToUI(string someParams)
{
    if(UIControl.InvokeRequired)
    {
        UIControl.BeginInvoke(()=>DoSomethingToUI(someParams));
        return;
    }
    //Do something to the UI Control
}
juharr
  • 31,741
  • 4
  • 58
  • 93