I’m using C# and Winforms in Visual Studio 2010
I have a program with which I am trying to read output through a serial port and print it to the screen. It originally started as a Console program but has now evolved to where we would like to have the output be in a field on a form. I have the code that parses out the output I’m looking for off the serial port written and working, I just need to change the Console.WriteLine to label.text = “”;, basically. I have merged the function that listens to the serial port into the GUI code so everything is in the same file.
I’m getting hung up on how to get the function to write to the label, though. It is STATIC so I cant just say ‘label.text =’. I tried creating a new form object inside the function to use, and that allowed me to access the control on the form, but doesnt update the form I see at runtime (I’m guessing because I’ve created a new instance of the form rather than accessed the existing instance?)
I need to have the serial listener run at the same time as the GUI as well, so the GUI label will update with the results it gets from running the function in close to real-time, so Ive tried to set it up to be threaded, with the GUI being one thread that is started by main() and the serial listener being another thread which is started when i click the button to start it. However, I run into the same issue with not being able to access the label in the serial listener thread because it has to be static to be initialized using system.threading.
I’m thinking maybe I need to use a background worker for the serial listener but I have absolutely zero experience with those. Would a background worker be able to update the label on the GUI in real time?
I cant post specific code but heres the general idea:
Main() starts GUIthread
GUI has button to start serial listener
OnClick button starts ListenerThread
ListenerThread outputs to console, want to output to a form label instead
Cant access GUI.Label because Listener is static out of necessity to be threaded
Creating new GUI instance inside Listener allows me to call the controls for that instance, but they dont update the GUI at runtime
have ensured label is public.
The
BackgroundWorkerclass was essentially made just for this.Just have the
DoWorkmethod do your actual work, and ensure thatReportProgessis called while working as needed. You can pass any data as astring(or whatever else, if you want) and then use that value in theProgressChangedevent handler, which the form can handle to update it’s UI.Note that the
BackgroundWorkerwill automatically ensure that theProgressChangedandRunWorkerCompletedevents run in the UI thread, so you don’t need to bother with that.Here’s a sample worker:
And here’s an example of configuring the background worker. Here I use lambdas both because it’s convenient to be able to close over variables (i.e. use variables across each of these anonymous methods) but if you wanted to you could refactor each of the event handlers out into methods.
Note here that none of the controls in the form are public, none of them are static, and I’m not passing any references to my form outside of the class. It’s considered best form each
Formto be responsible for updating it’s own Controls. You shouldn’t be allowing anyone else to directly access them. Rather than allowing some other worker class to directly access the label or modify it’s text, what’s happening is that the worker is simply telling the form, “Hey, I’ve got some data, you can go update yourself accordingly based on these values.” It is then the form that is responsible for updating itself. events are what you use to allow these workers, or other types of child elements (such as other forms you create, for example) to inform the “parent” form that it needs to update itself.