[RESOLVED] Communicating across threads from module to gui text box
I have tried to follow jmcilhinney's post at http://www.vbforums.com/showthread.p...Worker-Threads
I have a thread that relies on functions/subs that exist inside a module (I know people do not like modules since everything is pretty much public...but humor me :) )
The module has a sub that is supposed to write text to a textbox on the gui thread. That sub will be ran from another thread that is running the logic\processing, and not the gui thread. I was using delegates and checking for invokeRequired on the textbox before invoking the sub, but it just seems to do nothing. no errors, just nothing.
My code snippets are as follows:
Code in Module
---------------------
Code:
Public Delegate Sub WriteTo_txtLog_Invoker(ByVal LogEntry As String) 'DECLARED WITHIN MODULE BEFORE SUBS
Public Sub LogErrors(ByVal ErrMsg As String)
'TODO: handle writing error to file
'Write error to GUI TextBox
WriteTo_txtLog(ErrMsg)
End Sub
Public Sub WriteTo_txtLog(ByVal LogEntry As String)
If frmMain.txtLog.InvokeRequired = True Then
frmMain.txtLog.Invoke(New WriteTo_txtLog_Invoker(AddressOf WriteTo_txtLog), LogEntry)
Else
frmMain.txtLog.Text = LogEntry & frmMain.txtLog.Text
End If
End Sub
frmMain is the ....main form lol, on the gui.
It seems weird because it looks like I am following the process in that post above....but nothing happens even when i purposely call the logErrors sub from the logic/processing thread.
Any help would be greatly appreciated!
Re: Communicating across threads from module to gui text box
The issue is that you are using the default instance to refer to the form and default instances are thread-specific. InvokeRequired will never be True because referring to the default instance on the secondary thread simply creates a new instance on that thread. It belongs to that thread so InvokeRequired is False and the code goes ahead and modifies that instance, but it is not the instance that you displayed on the UI thread in the first place. You have two main options:
1. Add a property/field to that module to refer to the main form. Have the main form assign itself to that property/field in the first place, so you know that it refers to the correct instance.
2. Use the SynchronizationContext class.
If you use option 1 then you code doesn't change much. If you want to use option 2 then there's an example later in that CodeBank thread of mine.
Re: Communicating across threads from module to gui text box
Hmm, I apologize as I am still in the process of trying to learn more of the details to programming. could you elaborate on option 1?
I really do appreciate this help. You have been making understanding threading a much more clear task.
Re: Communicating across threads from module to gui text box
Your issue is nmot to do with threading.
Re: Communicating across threads from module to gui text box
Your Module references no instance to frmMain. Your are simply using it's default instance. Is there a particular reason you are using Module? And there really is no need to be writing a custom delegate.
Re: Communicating across threads from module to gui text box
I think that you're trying to make it harder than it is. You already know how to declare a variable and assign a value to it. That's all option 1 is.
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
freeblog
Your issue is nmot to do with threading.
Yes it is.
Re: Communicating across threads from module to gui text box
One thing I would add is that the problem is more due to modules than threading. Threading is the proximate problem, but the ultimate problem is more one of organization. People don't object to modules because they are "pretty much public" because they aren't. You make things public when you declare them public. If you declared elements of a module as Private, then they would not be Public....but they'd still be in modules. A module is a class with all members Shared. If you need a class with all members Shared, then a module is an excellent solution. In fact, it is an easier solution than actually creating a class with all shared members since you don't need to use the module name when refering to members of a module.
The problem with modules is that they are often used in place of a better design. They are not the wrong answer when they are used appropriately, but they are the wrong answer (as is anything else) when they are used inappropriately. In your case, the useage is inappropriate. After all, your method doesn't work on just any form, or even any instance of the main form. Instead, it works with only one specific instance of one specific form. If you try to use it for any other instance of any other form, it simply won't work. In this case, you actually ARE using it with another instance of a form, and that's where your problem lies, but you thought you were still working with the one instance of the one form, so it isn't quite the same thing.
The point of Object Oriented design is to encapsulate data, and the methods that work with the data, into a single code construct (a class). A module is no different, except that, since all the members are Shared, the class works with only a certain set of data (usually the union of the set of data passed to the method and the set of global data). In your case, you have the set of data with your main form and the set of methods that work on data in your main form (including the controls, which are just members of the main form) all in the main form....and then you have this other method that just happens to work with that main form and nothing else, but which is sitting off somewhere else in the program. A whole different file, in fact. That's pretty awkward organization:
All the things in here are the class....plus one other item that is found somewhere totally separate.
Re: Communicating across threads from module to gui text box
frmMain is what is loaded on startup. Is there a method of setting a variable within the module to the existing instance of frmMain?
I tried declaring a variable in the module as Windows.Forms.Form , then when frmMain loads, i set that variable = ME
will that then allow me to reference the particular instance of the form?
CODE IN MODULE
=================
Code:
Public frmMainInst As Windows.Forms.Form 'DECLARED WITHIN MODULE, BEFORE SUBS
CODE IN frmMain
=================
Code:
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
frmMainInst = Me
End Sub
Re: Communicating across threads from module to gui text box
Please read what has already been said. A module should not be used.
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
dontstealmyfish
frmMain is what is loaded on startup. Is there a method of setting a variable within the module to the existing instance of frmMain?
I tried declaring a variable in the module as Windows.Forms.Form , then when frmMain loads, i set that variable = ME
will that then allow me to reference the particular instance of the form?
CODE IN MODULE
=================
Code:
Public frmMainInst As Windows.Forms.Form 'DECLARED WITHIN MODULE, BEFORE SUBS
CODE IN frmMain
=================
Code:
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
frmMainInst = Me
End Sub
You've got the code already. Why ask us whether it will work when you could just try it for yourself? If it works then you don't need to ask the question. If it doesn't work then the question is not "will it work" but rather "why didn't it work".
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
ident
Please read what has already been said. A module should not be used.
Ok, but i would still need to be able to reference the form instance as I am trying to communicate across threads, right? That is what I am trying to figure out so that the invoking and invokeRequired will work.
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
jmcilhinney
You've got the code already. Why ask us whether it will work when you could just try it for yourself? If it works then you don't need to ask the question. If it doesn't work then the question is not "will it work" but rather "why didn't it work".
Ah, you are right. Sorry, I guess I was just nervous and posted before testing. It looks like it won't work when i reference the instance of the form itself, but will if i reference the instance of the textbox.
When I tried to reference the proper frmMain, it would do so... but then i could not access the textbox inside that form instance.
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
dontstealmyfish
When I tried to reference the proper frmMain, it would do so... but then i could not access the textbox inside that form instance.
That's because you declared the field as type Form and that type has no fields that refer to TextBoxes. If you know that the type of the object you want to refer to is frmMain then declare the field as that type. There's no reason not to. You'd only use Form if you want to be able to refer to different types of forms.
Re: Communicating across threads from module to gui text box
Quote:
Originally Posted by
jmcilhinney
That's because you declared the field as type Form and that type has no fields that refer to TextBoxes. If you know that the type of the object you want to refer to is frmMain then declare the field as that type. There's no reason not to. You'd only use Form if you want to be able to refer to different types of forms.
Perfect, Thanks! Definitely learned a few things today that I will not forget! declaring the variable as a type of specific form is exactly what I needed to do.