0

OK before everyone post duplicate let me inform you I have looked at all those other post and im still lost some say use delegates or background worker etc... but how would I make this thread safe i want to delete the files on its own thread.

here is the code that i am working with.

private void button1_Click(object sender, EventArgs e)
{
    cleanFiles.RunWorkerAsync();
}

private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
{
    if (listView1.CheckedItems.Count != 0)
    {
        // If so, loop through all checked files and delete.
        for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
        {
            string tempDirectory = Path.GetTempPath();
            foreach (ListViewItem item in listView1.CheckedItems)
            {
                string fileName = item.Text;
                string filePath = Path.Combine(tempDirectory, fileName);

                try
                {
                    File.Delete(filePath);
                }
                catch (Exception)
                {
                    //ignore files being in use
                }
            }
        }
        PaintListView(tFile);
        MessageBox.Show("Files removed");
        toolStripStatusLabel1.Text = ("Ready");
    }
    else
    {
        MessageBox.Show("Please put a check by the files you want to delete");
    }
}
Justin
  • 6,611
  • 3
  • 36
  • 57
partialdata
  • 93
  • 4
  • 14

3 Answers3

2

As Reed mentioned, you cannot access UI elements from a thread other than the UI thread itself. So, you'll have to pass on a delegate Control.Invoke() to be executed with the UI Thread, like this

Try

    private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
    {
        if (listView1.CheckedItems.Count != 0)
        {
            // If so, loop through all checked files and delete.
            for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
            {
                string tempDirectory = Path.GetTempPath();
                foreach (ListViewItem item in listView1.CheckedItems)
                {
                    string fileName = item.Text;
                    string filePath = Path.Combine(tempDirectory, fileName);

                    try
                    {
                        File.Delete(filePath);
                    }
                    catch (Exception)
                    {
                        //ignore files being in use
                    }
                }
            }

            PaintListViewAndSetLabel();
        }
        else
        {
            ShowMessageBox();
        }
    }

    private void ShowMessageBox()
    {
        if(InvokeRequired)
        {
            this.Invoke(new Action(ShowMessageBox), new object[0]);
            return;
        }
        MessageBox.Show("Please put a check by the files you want to delete");
    }

    private void PaintListViewAndSetLabel()
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action(PaintListViewAndSetLabel),new object[0]);
            return;
        }
        PaintListView(tFile);
        MessageBox.Show("Files removed");
        toolStripStatusLabel1.Text = ("Ready");
    }
Bala R
  • 107,317
  • 23
  • 199
  • 210
  • Thank you for all the help ! i am processing all the information !! ;] lol ! – partialdata Apr 11 '11 at 19:09
  • I tried the code above same issue do it freaks out on the if (listView1.CheckedItems.Count != 0) do i need to move this out of the background worker and just use threads? – partialdata Apr 11 '11 at 19:26
  • Usually getting something from a view should be fine; it's just setting something requires calling `Invoke()` – Bala R Apr 11 '11 at 19:29
0

The problem is that you can't access any properties of your ListView (listView1) from the background thread (ie: anything inside of the cleanFiles_DoWork method) directly. User interface controls can't be accessed on any thread other than the user interface thread.

You should, instead, make a list of the items to "clean" before calling DoWork, and pass these into the method via the RunWorkerAsync overload taking an object, and retrieve it in your method via DoWorkEventArgs.Argument.

This will allow you to pass a list of items to process, process them in the background, then update your list when you are complete.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • would please be so kind to show me an example with my code above? – partialdata Apr 11 '11 at 20:23
  • you talk about making a list, is there a way when items are checked it adds that file with the path to an array ? then when you hit clean it sends that array list to the clean file method and then starting a thread and deleting the files ? – partialdata Apr 11 '11 at 20:49
0

Its bad idea to use control from background worker, I had the same problem recently with TreeView control. So the solution for Thread-Safe Calls to Windows Forms Controls is How-to article from microsoft. The main idea it checking safty using InvokeRequired property of your control and, if nessesary, run method invocation through Invoke method which is thread safe.

Anton Semenov
  • 6,227
  • 5
  • 41
  • 69