How to use Control.Invoke to update a form element from another thread

HastaLaVictoria

Newcomer
Joined
Aug 26, 2005
Messages
3
Location
Manchester, UK
G'day X.NET!

I have a dilly of a pickle here, wondering if anyone can help a neighbourino out. </flanders>

I have an application I'm building that uses asynchronous TCP connections to ferry data about between a server and multiple clients. I'm trying to implement a TreeView on my server UI form that will display all the connected clients' usernames.

The problem I'm having is that I've written a method populateUserTree(), and called it from my receiveEvent() method, which is an AsyncCallback for BeginReceive. Whoops! Doesn't work, as the thread I'm in can't access the controls on the form. The error message hints at using Control.Invoke to achieve this, but the MSDN page on it isn't all that helpful.

I took a stab in the dark and had my receiveEvent method call treeClients.Invoke(populateUserTree);, but that didn't work. The compile error was that a 'method group' could not be converted to a 'Delegate', so I presumed I got it horribly wrong and went on an Interwebs search for the answer. I found an MSDN article on delegates but it wasn't explaning what I wanted.

Alas, nothing. So, in closing, can anyone provide an explanation, or example, of how to use Invoke to get a TreeView on a form to update, originating in another thread?

The code I'm using to perform the actual updates to the TreeView treeClient is:
Code:
        treeClients.BeginUpdate();

        treeClients.Nodes.Clear();
        treeClients.Nodes.Add("Connected Clients");

        foreach (ClientItem clientInfo in clientList)
        {
            treeClients.Nodes[0].Nodes.Add(clientInfo.strName);
        }

        treeClients.EndUpdate();

Thanks to anyone who can help.

-Dru
 
Huzzah! Got it working.

I found a good explanation of thread invocation. It was in fact one of the results on my Google for Control.Invoke, it just didn't have a title that screamed out at me.

The trick, it seems, is to recursively invoke the method that's going to do it. My problem was that I wasn't specifying a delegate correctly. Here's the code I ended up with:

Code:
        private void populateUserTree()
        {
            if (treeClients.InvokeRequired)
            {
                treeClients.Invoke(new MethodInvoker(populateUserTree));
            }
            else
            {
                treeClients.BeginUpdate();

                treeClients.Nodes.Clear();
                treeClients.Nodes.Add("Connected Clients");

                foreach (ClientItem clientInfo in clientList)
                {
                    treeClients.Nodes[0].Nodes.Add(clientInfo.strName);
                }

                treeClients.EndUpdate();
            }
        }

So when one of my threads calls populateUserTree, if (treeClients.InvokeRequired) checks to see if the current thread is able to play with the treeClients object. If it can't, it calls treeClients.Invoke(), passing a MethodInvoker object initialised using the same method that just called it, meaning the method is called again, one thread up in the ownership hierarchy (please correct me if that observation is wrong, or uses inadequate terminology - I don't want to mislead anyone by not using the right explanation).

This process repeats until invocation is no longer required (i.e. we're in the right thread), dropping into the else block so that I can update the TreeView treeClients.

-Dru
 
Last edited:
Back
Top