Cannot change a property of WPF from a websocket event - c#

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);

Related

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.

Get the owner of thread that is executing

when I run the project I receive the famous "Calling thread cannot access..." exception. Now, first I would like to see why is this happening, since my code should not be creating this new thread at this stage, so I would like to know who created this thread.
When exception occurs, StackTrace reports that the method was called from external code (only two items in StackTrace).
Threads window reports its Priority only (no explanation in Name).
How can I get more information about the current thread running? Like which library created it? Is it external code or mine?
Thread.CurrentThread should tell you all what you need to know about a managed thread. If "Threads window" doesn't shows name means, there is no name specified.
Also there is no way you could find which library created the thread. No such information stored anywhere.

Multi-thread debugging with VisualStudio and WebBrowser Windows.Forms controls

We're creating a few threads in a Windows.Forms solution.
We've also got a BrowserControl (yup, it's OAUTH) and of course I'm finding issues with debugging -
Cross-thread operation not valid: Control 'xxForm' accessed from a
thread other than the thread it was created on
And yet I am calling 'correctly'
xxForm.Show()
by ensuring it's wrapped in an invoke call
.Invoke(new MethodInvoker())
and still I get the thread issue. I can do everything else (Focus, BringToFront) it's the Show that errors.
Moreover, the GUI never gets the browser response and shows. In the VS debugger I get the above threading erropr (apartment state of background thread == MTA). When run as an EXE the same code has a threading aparement of STA and the GUI will never show when debugging, but if I run the EXE directly, there's no threading issue, the browser control just never responds to input.
Spo the questions are:
Why the different behjaviour in VS / EXE?
How do I debug in VS?
Does the BrowserControl play ok with multiple threads?
Update
YES I KNOW there's no code - it's too long. I'll see what I can do.
Also please read the question before posting an answer. I am invoking the background thread on the UI thread. That's not the issue. This has NO EFFECT on the result. I'll down vote answers that recommend that.
Also some hope - I've searched for many hours. It's linked the the message pump. Unless the message pump is running the DocumentCompleted event isn't received.
Update 2
Best I manage is pseudo code:
Program:
startWorkQueue
LoadForm (don't show)
Thread1:
addToQueue
Thread2:
readFromQueue
ShowForm (on occasion)
Now the ShowForm method is on a Windows.Form control.
Within this any call is made via an Invoke, so that despite the 2nd thread making the call the ShowForm, the actual .Show() etc etc calls are on the UI thread.
So what am I missing? I just don't understand why there's a cross thread exception....
Ok I've found out what was going on and I'll post here for reference.
I hope it helps someone in the future.
We had some different constraint to the vanilla Forms applications - our Forms were created on the Main thread but had Show() called on a different thread. We also don't have a starting UI - we sit in the background and sometimes react to events with UI prompts.
As such a number of issues hit us. Rather than list them all I'll detail our takeaways:
Application.Run
If decide NOT to Show a Form at the start of your application… then you'll need to consider threads carefully (see Form.Show notes)
Form.Show
This does all resource allocation etc, NOT the Load/ctor
Performs handle creation / resource allocation
Handle creation
Hwnd
If we attempt to access certain Form properties before it has Show(n) then you'll need to create a handle manually (or an Exception is created)
• As easy as if (!IsHandleCreated) { CreateHandle(); }
HOWEVER
This create the control/form
Therefore the control/form is created on the Thread that calls the Handle create
This must be the same UI thread (STA) as the Main function
• Otherwise much weirdness occurs
SO
You aren't restricted by what to do with Application.Run
You can access properties in .Show (but you may need to create a handle first)
You can call Show from a different thread, but ensure the handle is ONLY created on the main thread
I hope it helps, I can provide more details on our specific problems if need be.
Various aids that helped included displaying ManagedThread AND ProcessId in the log and scouring MSDN.
Since the code has not been pasted, I would like to remind you that in WinForms, the UI elements should be accessed only on the UI thread. Any other thread apart from UI thread should not be updating the UI elements directly.

Retrieving properties from a GUI object in a thread

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.

Is BackgroundWorker a good subsititute for AsyncOperationManager?

Here's what I'm trying to solve:
My class (which could be hosted by an UI app or a windows service or whatever), needs to receive windows messages. Somewhere around here, someone gave the suggestion (and some source code) to create a windows form in a separate thread that will create the form and whenever a windows message that I'm interested in receives on the WndProc, it triggers a delegate using context.Post.
I've been trying to make it work but unsuccessfully. Instead of spending more time on that avenue and before I try to replicate the problem I'm having there to post here for help, I'm thinking I'm going to try to implement the same solution using BackgroundWorker.
From the tests that I've done, I would expect it to work pretty good when I'm using UIs, but my question is: is there any advice against using BackgroundWorker when not dealing with UIs?
Edit:
The way I'm envisioning it, every time my "child" form (the one running in the background worker) receives a message, I will issue a ReportProgress. The only thing that I need to pass through threads is the message ID, so technically it should suffice right?
BackgroundWorker and a window are water and fire. A window requires an STA thread and a message loop, neither are provided by BGW. Check my answer in this thread for an alternative.
I would say if its at most every 5 seconds, then you should be fine passing the message id (as userState) back via the ReportProgress event.
The BackgroundWorker object is an excellent method of performing the tasks you're looking to perform. You may, however, find that a simple message ID is no longer sufficient when you get things coded up, but the BackgroundWorker.ReportProgress method allows you to pass in a state object. If you code up an efficient state object you can literally send back thorough snapshots to report back to the parent form.

Categories