0

This is the method:

private TreeNode CreateDirectoryNode(string path, string name)
        {
            var directoryNode = new TreeNode(name);
            var directoryListing = GetDirectoryListing(path);

            var directories = directoryListing.Where(d => d.IsDirectory);
            var files = directoryListing.Where(d => !d.IsDirectory);

            foreach (var dir in directories)
            {
                i ++;
                directoryNode.Nodes.Add(CreateDirectoryNode(dir.FullPath, dir.Name));
                int percentage = (i + 1) * 100 / 100;
                backgroundWorker1.ReportProgress(percentage);
            }
            foreach (var file in files)
            {
                directoryNode.Nodes.Add(new TreeNode(file.Name));
            }
            return directoryNode;
        }

Then in background do work:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {            
            var root = txtHost.Text;
            treeView1.Nodes.Clear();            
            treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));           
        }

And the progresschanged:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripProgressBar2.Value = Math.Min(this.toolStripProgressBar2.Maximum, e.ProgressPercentage);
        }

After 20 seconds of work it throw exception in the DoWork event on the line:

treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));

InvalidOperationException

Action being performed on this control is being called from the wrong thread. Marshal to the correct thread using Control.Invoke or Control.BeginInvoke to perform this action

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Action being performed on this control is being called from the wrong thread. Marshal to the correct thread using Control.Invoke or Control.BeginInvoke to perform this action.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.TreeNode.Realize(Boolean insertFirst)
       at System.Windows.Forms.TreeNodeCollection.AddInternal(TreeNode node, Int32 delta)
       at FTP_ProgressBar.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in c:\ftp_progressbar\FTP_ProgressBar\Form1.cs:line 419
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 

Line 419 is: treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));

  • 1
    In your DoWork method you are trying to manipulate an UI control that has been created on the UI thread. You can't access that control from another thread. If you got a 20 seconds delay before breaking apart I would say that you are pretty lucky – Steve Dec 03 '14 at 16:37
  • possible duplicate of [How to update GUI with backgroundworker?](http://stackoverflow.com/questions/1862590/how-to-update-gui-with-backgroundworker) – WeSt Dec 03 '14 at 16:37

2 Answers2

4

You can't directly modify UI elements from a non-UI thread. When using a BackgroundWorker, the best place to modify the UI thread is from the ProgressChanged or RunWorkerCompleted events.

First, pass the values from the UI via the RunWorkerAsync() method:

backgroundWorker1.RunWorkerAsync(txtHost.Text);

Only do non-UI work in the DoWork event, then pass the results to the RunWorkerCompleted event:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{            
    var root = Convert.ToString(e.Argument);  // txtHost.Text;

    var dirNode = CreateDirectoryNode(root, "root");

    e.Result = dirNode;
}

Subscribe to the RunWorkerCompleted event to update the UI:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    var dirNode = (TreeNode)e.Result;

    treeView1.Nodes.Clear(); 

    treeView1.Nodes.Add(dirNode);
}

The app may freeze momentarily while the TreeView is being updated in the RunWorkerCompleted event, but you won't get that particular exception.

Grant Winney
  • 65,241
  • 13
  • 115
  • 165
  • Grant it does working. But what about updating the progressBar ? In my code i did wrong calculation in the method with the i++ abd the int percentage = (i + 1) * 100 / 100; and in the ProgressChanged event it does updating the progressBar but it's not getting to the end to 100% the green bar when the operation end is not even in the 50% – Horhe El Fenenado Dec 03 '14 at 16:56
  • toolStripProgressBar2.Maximum is set to 100 in the designer. Either then that i didn't do any calculations. – Horhe El Fenenado Dec 03 '14 at 17:25
0

The DoWork event runs in a background thread. It cannot interact with UI elements. You should be creating some result; something that is not itself a UI element, setting it to the BGW's Result property, and then updating the UI based on that result in the RunWorkerCompleted even handler, which can access the result set in DoWork.

Servy
  • 202,030
  • 26
  • 332
  • 449