views:

165

answers:

4

So I want to make sure all of my database / network operations are not happening on the UI thread of my application. To do this I normally use the BeginInvoke function to make the call and then Invoke to do the actual update. I am not sure if I am doing things correctly compared to the way it should be done. Could anyone please provide comments on the following code:

   private void folderTree_NodeExpandedChanged(object sender, RadTreeViewEventArgs e)
    {
        if (e.Node.Tag != null)
        {
            var path = (string) e.Node.Tag;

            if (!string.IsNullOrEmpty(path))
            {
                if (Directory.Exists(path))
                {
                    folderTree.BeginUpdate();

                    BeginInvoke(
                        new Action(() => GetDirectories(path, e.Node)));

                    folderTree.EndUpdate();
                }
            }
        }
    }

    private void GetDirectories(string path, RadTreeNode parent)
    {
        var dirs = (new DirectoryInfo(path)).GetDirectories();

        Array.ForEach(dirs, d => Invoke(new Action(
                                            () => AddNode(d.Name, d.FullName, parent))));
    }
+3  A: 

On a control/form, BeginInvoke pushes work to the UI thread, via the message pump (with a small overhead incurred for the privilege). So you've gone from the UI thread to the UI thread... I suspect you want a BackgroundWorker / ThreadPool or similar in here somewhere... (perhaps ThreadPool would be easiest from the current position).

Also; you probably don't want to do the update work synchronously, and you don't want lots of switches between the threads; I'd pass the entire array over (or mid-size chunks); not individual records.

Marc Gravell
A: 

As far as I can tell, the following call:

BeginInvoke(new Action(() => GetDirectories(path, e.Node)));

...is very little different to this one:

GetDirectories(path, e.Node);

It only adds an extra layer or two around the call, but there is no asynchronosity in there; it all happens on the same thread. You will need to include some mechanisms to push the work to another thread (BackgroundWorker control, use the ThreadPool or something similar)

Fredrik Mörk
A: 

You might find the BackgroundWorker class, an easier option.

Mitch Wheat
A: 

I would do it like this. Haven't tried this code out though, but it should work.

      public class ParameterInfo
        {
          string _path;
          RadTreeNode _parent;
        }          

    if (!ThreadPool.QueueUserWorkItem(new WaitCallback(GetDirectories),  
                                 new ParameterInfo  
                                 {  
                                      _path = path,
                                      _parent = e.Node
                                 }))  
       {  
          //should log, if a thread has not been created  
       }  

         private void GetDirectories(ParameterInfo param)
         {
                var dirs = (new DirectoryInfo(param._path)).GetDirectories();

                Array.ForEach(dirs, d => BeginInvoke( new Action( 
                            () => AddNode(d.Name, d.FullName, param._parent) )
                            ));
         }
Stan R.