How to Pass data from a Thread back to the Calling Form [C#/CS 2005]

Shaitan00

Junior Contributor
Joined
Aug 11, 2003
Messages
358
Location
Hell
Background information - I have a main form (fBoard) that creates & starts a listener thread (thTcpListener) which is responsible for receiving incoming network data from the server.

So, my question is pretty much two-fold:
- How do I pass the data that was recieved from the Thread (thTcpListener) to the main form (fBoard)?
- How do I then notify the main form (fBoard) that data is ready and waiting to be used?

Specifically - the data recieved in a custom object (objCustom) and fBoard has a "private ObjCustom objCustom" member that needs to be updated with this incoming data when it arrives.
The main form (fBoard) will create & start the listener thread (thTcpListener) and wait for it to recieve the objCustom.
When the object is recieved the thread should "somehow" pass it to fBoard and notify it that data has arrived, fBoard will then process the object and again wait for the next objCustom to arrive, this will happen continously (as the application is running)...

As for the notification, this is going to be tricky ... The user is interacting with fBoard so I can't just Wait on the thread to return data (like using a ManualResetEvent) - I was thinking of simply using a DELEGATE function to solve my problem...
So when the thread recieves the data call the Delegate Function on the main board (fBoard) and it can do all the work for me (including possibly passing the data?)

Other then using somekind of a delegate I have NO CLUE how to "pass the object/data" from the thread to the main form (fBoard)... This is where I really need help...
I was thinking I could use something like a QUEUE that I would share (using a ReaderWriterLock to make it threadsafe) or something along those lines - but is there something better? or something intended for this situation...

Anyways - I think I can solve this using some trial-and-error (via delegates) but I want to ensure I am using a conventional and secure method....
Any ideas, hints, and help would be greatly appreciated, thanks
 
Correction - not sure I can use DELEGATES for this anymore (unless someone can confirm)... I currently use them for my thread to set a LISTBOX of my main form (fBoard), but this requires I use "if (this.ChatListBox.InvokeRequired)" which does NOT exist for my custom object (objCustom) ...

So I am back to square 0 ...
Any ideas?

Can I create or use some kind of EVENT (or custom event) to handle this situation?

Thanks,
 
Last edited:
Invoke

Sure you can use a delegate, like so:

C#:
fBoard.Invoke(theDelegate, new object[] {objCustom});

The Invoke method ensures the delegate is executed in the thread which created fBoard, and so carries objCustom across the thread boundary. If this call is always being made from another thread, then there would be no need to check InvokeRequired as it would always return false.

Good luck :cool:
 
And this would be an acceptable & threadsafe way to:
1- Pass in the data from my Thread
2- Perform the required processing on fBoard (loading the data, rendering the data, etc...)
Without affecting fBoard itself (that could be used by the User, so not blocked)?

I mean my delegate function will be rather long/large as there is a lot of work for it to do - this is completly acceptable? Because if so it would be a really cool solution for my current situation :) So this can pretty much replace the need for AutoResetEvent and Locks and shared queues, etc... and would be just as safe...
 
There's only one UI thread.

  1. Yes
  2. No

Using Invoke causes the delegate to be executed on the UI thread, so the UI will be unresponsive while it is executing. I guess I misunderstood what you meant by notifying the main form that data is ready and waiting to be used. Should it be informed after this long processing, or is this processing what it should do when it is informed? Infact, what does 'informed' even mean in this context?

If the lengthy processing of the data involves interacting with the form's controls, then either it must be executing in the UI thread, or each interaction with the form must be performed using Invoke (to marshall that particular action to the UI thread).
 
Oh - while it is processing, the fact that the UI is unresponsive is perfectly fine (and is expected) - sorry for that...

So, I wasn't 100% sure how to implement this, I did some research and I found a method that works but I wanted to fly-it-by-you to see what you thought (is this okay, is there better? etc...)

So, what I did was created a Delegate CallBack function and a work function on fBoard, I then pass fBoard to the Thread when I launch it (so the thread itself has a "pointer" to the real fBoard). And in the Thread I use fBoard.CallBackFunction to do the work - as I said it WORKS but I want to ensure it is okay...

Here is the CODE - tell me what you think - or if there is a better way to do this...

fBoard Code:
Code:
// Delegates
// Used to perform Updates on CustomObject
delegate void SetCustomObjectCallback(CustomObject _objCustom);
public void SetCustomObject(CustomObject _objCustom)
{
        if (this.InvokeRequired)
        {
            SetCustomObjectCallback d = new SetCustomObjectCallback(SetCustomObject);
            this.Invoke(d, new object[] { _objCustom});
        }
        else
        {
            // Load new Custom Object
            objCustom = _objCustom; // this is the magic

            // Do the processing of the new Custom Object here
            ....
            ....
            ....
        }
    }
}

Thread Code:
Code:
fBoard.SetCustomObject(objCustom);

... hope I am not making any fundamental mistakes...
Thanks a lot for the help.
 
Correct

Yes that is a good approach to cross-thread callbacks, and should work as intended. However, you could avoid the delegate being invoked twice by calling Invoke directly from the other thread.

C#:
//Instead of:
fBoard.SetCustomObject(objCustom);

//You could use:
fBoard.Invoke(fBoard.SetCustomObject, new object[] {objCustom});

//Or in .Net 1.0 or 1.1:
fBoard.Invoke(
            new SetCustomObjectCallback(fBoard.SetCustomObject),
            new object[] {objCustom}
             );

Good luck! :cool:
 
Oddly enough neither approach seems to work, they both generate the following errors:

Method (1) errors:
Error 1 The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delegate, params object[])' has some invalid arguments
Error 2 Argument '1': cannot convert from 'method group' to 'System.Delegate'

Method (2) errors:
Error 1 The type or namespace name 'SetCustomObjectCallback' could not be found (are you missing a using directive or an assembly reference?)
Error 2 The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delegate, params object[])' has some invalid arguments
Error 3 Argument '1': cannot convert from 'SetGameLevelMapCallback' to 'System.Delegate'

I even tried making the DELEGATE (in fBoard) public but that didn't seem to help...

BTW - I am using VS C# 2005, .NET 2.0.
Thanks,
 
Use older code

Ah, you've defined the delegate inside the fBoard class? The you would need to qualify the name of the delegate with the name of its containing class. Alternatively you could move the definition of the delegate outside this class.

However, I would recommend just going back to the code from post 6. It works essentially the same way but the delegate invokation is within the method itself.

:)
 
Back
Top