Shaitan00 Posted November 12, 2006 Posted November 12, 2006 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 Quote
Shaitan00 Posted November 12, 2006 Author Posted November 12, 2006 (edited) 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, Edited November 12, 2006 by Shaitan00 Quote
MrPaul Posted November 12, 2006 Posted November 12, 2006 Invoke Sure you can use a delegate, like so: 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: Quote Never trouble another for what you can do for yourself.
Shaitan00 Posted November 12, 2006 Author Posted November 12, 2006 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... Quote
MrPaul Posted November 12, 2006 Posted November 12, 2006 There's only one UI thread. Yes 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). Quote Never trouble another for what you can do for yourself.
Shaitan00 Posted November 15, 2006 Author Posted November 15, 2006 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: // 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: fBoard.SetCustomObject(objCustom); ... hope I am not making any fundamental mistakes... Thanks a lot for the help. Quote
MrPaul Posted November 15, 2006 Posted November 15, 2006 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. //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: Quote Never trouble another for what you can do for yourself.
Shaitan00 Posted November 15, 2006 Author Posted November 15, 2006 And leave the FUNCTION itself (SetCustomObject) in fBoard as-is? Thanks ! Quote
Shaitan00 Posted November 16, 2006 Author Posted November 16, 2006 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, Quote
MrPaul Posted November 16, 2006 Posted November 16, 2006 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. :) Quote Never trouble another for what you can do for yourself.
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.