Retrieving properties from a GUI object in a thread - c#

I have a C# program that executes a thread. Inside this thread, I have the following code:
string strDropDownValue = (string)ddlVersion.SelectedItem;
I am trying to retrieve the selected value from the drop down list. This line works, obviously, in a single threaded application. Because I'm doing this from a thread though, I get a cross thread exception at runtime. I know that if I want to change a value of a GUI object from a thread, I need to use InvokeRequired() and Invoke(). However, what do I do if I just want to read a property value? Do I still need Invoke()? I tried looking for a solution to this but couldn't find an example. All the examples I found show how to set a property, but not how to read it. Any help would be appreciated!

Yes, you would still need to invoke, and pull the string out of the control on the UI thread. You can then pass it back into your other thread via some synchronized variable, or something similar.
That being said, typically, you would pull the information out of the control before you start your background thread, and just pass it into the background thread. That's why, I suspect, you don't find many pieces of code showing how to accomplish this.

Related

C#: Is there a way to access the main thread for a little while and go back to secondary thread?

I am using WinForms and I am stuck. I am invoking a new Thread to do some background data checking. When checking for data, it needs to create a new Control element.
In order other features not to act up, I want the main UI thread to create the element. To do that, I have to switch back to my main thread, create the element there (accessible globally), switch back to the second thread and add necessary features.
My goal is to create a control where the owner of the control is the main UI, but the event fired to create the control is from a secondary thread. How do I do this?
I hope my question is not too confusing
Thank you everyone for all the comments. Apparently, the easiest way to implement it was using a background worker as #SimonPrice said. It is much easier than creating a new thread inside a function that does the background task
I had to restructure the code, but now it's cleaner and more efficient. Moreover, the cross-thread manipulation error is easily handled now.
Thanks again

Cannot change a property of WPF from a websocket event

I am trying to change a property of WPF from a websocket event however I am encountering a problem where I get this exception: https://i.imgur.com/lsFt3OR.png
I googled the exception and it brought up this Microsoft article: https://learn.microsoft.com/en-us/dotnet/api/system.invalidoperationexception?view=netcore-3.1
They said that I could use Dispatcher.Invoke to remove the exception (as seen in the screenshot). I did that on a render thread but I still get the error.
enter image description here
Secondly I tried to invoke the function the dispatch the thread onto the main thread which resulted into the error in the attempted solution. Strangely enough I had access to change the property according to the print debugging I did.
enter image description here
I know this is an old thread but I have run into this same issue in my searching and if this is more clearly answered others may find it helpful. That said what Andrej Dobes is correct this may just provide more clarity.
Based off of your response to the previous answer it looks as though you were still confused. The code would need to look similar to this on line 49 of your previous screenshot:
PlayerDataSocket.OnMessage += Application.Current?.Dispatcher?.Invoke(PlayerDataSocket_OnMessage)
The ? are added as not null checks and aren't necessary for your situation most likely.
You need to use the dispatcher of the thread that created the object originally which I guess would be the UI thread since you're setting the image. When invoking dispatcher from static class directly you always get the one that is actually assigned to the actual thread, which means you would have to have the reference to a dispatcher of the thread that owns the object.
DispatcherPriority.Render does not say that you want to exeucute it on a render thread but it's setting the priority when it should be executed, you check more at msdn about that.
To access the UI thread dispatcher you can use the code below, but then the UI thread actually needs to be the owner of the object you're setting
Application.Current.Dispatcher.Invoke(action);

Fundamental question about synchronizing with the UI thread in Winforms using c#

I know Winforms has only one UI thread, and if you need to update it while you are on another thread, you should use invoke method.
My questions is if what you are doing does not change the look of any control, would that still be accessing the UI thread?
For example, my form1 has a logger which write messages to a local file which users don't see at all. If I use the logger in another thread, say write a new message, would this be considered accessing the UI thread? Yes, logger is initialized in form1.cs, but it has no visual representation on the form at all. Do I still need to use invoke?
Also, if I have a custom control which extends a textbox. The custom control has a property called initialized. Changing this property has no effect on the look of the control whatsoever. Then, if I update this property from another thread, do I need to use the invoke method?
If only one thread uses the logger instance, no need to synchronize, else if several threads can write to it, you need to synchronize, not with the UI thread but between threads, using lock or monitor for example.
It is the same thing for the last question.
Simple experiment seems to say if you are not changing the looks of a control, then you are thread safe.
You can see in the screenshot, when I set a member of my form call blnButtonDown(a bool), it was OK. When I changed the name of a textbox of my form, it was still OK. It was only when I changed the textbox's text, which changes the look of the form, that I got an exception thrown.
So my tentative conclusion is that if you are changing a form/control from another thread, you don't have to use invoke if your changes do not change the look of the form/control.

Writing a Multi-threaded C# application

I need to write an application in c# that keeps track of multiple tasks, each being implemented as a class instance running on its own thread. A user interface will be used to display the status of each task instance depending on which task I select from tree view which will display the list of tasks.
An idea I have is to create some other class, called PropertyClass which will have an instance of the TaskClass and some properties relating to this TaskClass instance. Then whenever the TaskClass instance changes its state the related property in the PropertyClass instance will get updated and then the UI will be updated with these property values from the PropertyClass when the task is selected from the Tree View list.
There will probably be hundreds of these tasks running which will be communicating with a service on a remote machine.
How else can I go about coding this solution in an efficient way?
Read this document from the MSDN on the Task Parallel Library first.
I have a few suggestions.
First, you need a way to make sure you don't end up with threads blocking your app from closing. One sure fire way to do this is to make sure all your threads are background threads. That can be a little problematic if you have to make sure a thread's work is done before it is joined or aborted.
Second, you could look at using the ThreadPool class which should make creating and using threads more efficient. The thread pool is there to help you manage your threads.
Third, you will need a method of synchronizing your data access from the GUI to data in the other threads. In WPF you use the Dispatcher and in WinForms you'll use Invoke.
Forth, the BackgroundWorker class can help with all of these if it'll fit in the model of your application.
Fifth, events and delegates can be BeginInvoked which essentially puts them on another thread. It's kind of implicit multi-threading and can be useful.
Sixth, and I've not yet had the chance to use this, .Net 4 has the Parallel Task Library that may be of use to you.
Seventh, safe shared data access and synchronization can be accomplished using lock and/or Monitor.
Hope this helps.
-Nate
If each TaskClass instance corresponds to a node on the tree view, you can store the TaskClass instance in the tree view item's Tag property. Or you could create a dictionary of TaskClasses, keyed by a unique identifier such as a GUID, and store the identifier in the Tag property.
In either case, use a callback method to signal that a TaskClass instance has an update.

How do I keep a form from going blank while my program working with out using a background worker?

On a regular basis I find myself writing little utility programs that use some loop which takes a while to process. Yet while the loop is going the form no longer refreshes so if you were to move the form, or move another window over it and off, the form would be blank until the loop finishes.
Now I know the correct way to deal with this is to use a background working to do the time consuming task on a separate thread. But I haven't quite got my head around the multi threaded stuff just yet.
So If I'm only going to use one thread what is the best thing to do on each loop to keep the contents of the form up to date. For example there may be a progress bar in the form.
I've seen and used various combonations of Form.Refresh(), Form.Update(), and Application.DoEvents() but was wondering what is the best way to deal with this?
You can fake it with Application.DoEvents() at different locations in the code, but you really should put the work in another thread.
Take it as an opportunity to get into threading, you will have to sooner or later.
The Bgw makes it easy: The DoWork event runs on another thread but ProgressChange and Completed are synchronized on the main thread.
Find a few examples and be careful when you use shared data inside DoWork.

Categories