I followed this tutorial on http://www.dotnetspark.com/kb/1867-create-tab-control-wpf.aspx to create closable tabs for a WPF application.
I'm creating a multithreaded application and I'll be using closable tabs from the link above. I want each thread to have its own tab and update it as it runs. Should I create the tab inside the new thread or create the tab in the main thread and update it from the new thread? What is the proper way of doing this?
How can I make the thread end when the tab is closed?
Regards!
Neither. Have the main thread create the tab, update the tabs when directed to do so by the various other threads, and command the thread to terminate when the tab is closed.
Learn how to use the dispatcher to coordinate threads.
If a thread does some work that, by the program logic, should not be done at that time, that thread's code is broken. Fix it. If the thread is not supposed to continue running when the tab is closed, code it not to continue running when the tab is closed. Don't leave the thread broken, coded to do work when that work should not be done by program logic, and then try to fix it someplace else.
This is a backwards way of thinking about threads. Threads are just vehicles that do work. You control them by controlling the work. You write every line of code that the threads execute. If you don't want a thread to X in condition Y, code it not to do X in condition Y.
In sum, if program logic says work X should not be done when tab Y is closed, do this:
1) Somewhere, store a flag that indicates whether work X should be done or not.
2) In the code that does work X, check this flag. If it's set to no, don't do the work. By program logic, the work should not be done. Doing it is broken.
3) When the tab is closed, have the UI thread set the flag to stop doing work X.
Tabs should not correspond to threads. That makes no logical sense. Tabs should correspond to whatever is displayed in the tab. (They may 'happen to' correspond to threads indirectly, but this is not primary. Threads really correspond to whatever work is associated with the tab.)
In principle, if a different thread took over the same work, shouldn't it still be in the same tab? Or should the same data suddenly go in a different tab just because a different thread is producing it? That you happen to always do the work that goes in that tab in the same thread is an implementation detail that should not be reflected that way in the architecture. As you have learned, that just creates silliness where you have to figure out which thread is doing the work when you really don't care.
You'll have to use the UI thread to render/display tabs. See this link(archive). As the title says "Build More Responsive Apps With The Dispatcher".
Related
I am a beginner on C#. There is a project I am working on need to use 2 threads. The main one is for displaying the usual Wpf pages. Another one monitoring the inputs from hardware. If there is a desired input signal detected, the whole system should stop and shows a warning page on the window, which is controlled by the main thread.
Now I get stuck on how to do the deal with the threads when the input signal detected. Should I pass a signal to the main thread, and ask the main thread to display the warning page, and stop the secondary thread. Or I should let the secondary thread display the warning page directly, and take over the control priority from the main thread?
Or I should let the secondary thread display the warning page directly, and take over the control from the main thread?
That makes literally no sense at all.
Should I stop the secondary thread and pass a signal to the main thread, and ask the main thread to display the warning page.
That also makes no sense at all, but at least there's a gleam of sort of what you mean here. To be absolutely clear, there's no such thing as "stopping threads" as you mean.
But yes, you send a message to the GUI thread to update its state, specifically using Dispatcher.BeginInvoke in WPF.
WPF, like most GUI toolkits on Windows at least, has sticky controls - which essentially means they have thread affinity and cannot be accessed from other thread which didn't create them. [You can verify that from source, there are calls to VerifyAccess() littered all over the place.]
That design constraint rules out the possibility of other thread "taking over" anything from another thread, ever.
But the world doesn't end there, and cross-thread communication is common enough requirement that the designers have provided you with the means to satisfy the same thread requirements yet send messages across threads.
The way to do that lies with two members of Dispatcher object each WPF window has. You can read the full details here and on associated pages for that type, but roughly it goes like
protected void Button_Clicked(object sender, EventArgs args) =>
Dispatcher.Invoke(() => { /* Your method body which will be executed on the proper thread. */ });
If you prefer asynchronous communication, you can use either BeginInvoke or InvokeAsync instead.
I inherited a winforms app. It uses a third-part-closed control that renders documents and photos... It has only sync methods for opening a document. The problem is that my clients are dealing with really big documents (in the area of 2GB!!!) and opening these docs really "block" the UI thread... which is bad...
Common sense would make you think "Just off-load it to a background thread" but the question is "HOW"! See, to alter the control (because calling "Open" causes it to be altered) I need to Invoke it, and that causes the code to run o UI thread again... locking it up...
So I turned the table upside down. What if instead of creating the control on the main thread and passing it to a background thread for processing, I could create the control on the background thread, load it up (avoiding this way the cross-thread exception) and, when done, feed it to the main thread?!?
Right now what I need is to know how to definitively handle a control to another thread, and not only temporally...
I'm not sure if this is possible but you could try to:
create a new form on a secondary thread (this form will host your fancy control)
load the document from this secondary UI. It will be blocked but you can hide it and only display a
loading message on the main UI.
when the job is finished transfer the 'work' to main UI and main thread.
It's just an idea.
What you are asking to do is impossible. A Winforms control's thread affinity is determined when that control is created, and it cannot be changed.
The best solution is to not use that control. I doubt there's anything it does that cannot be implemented correctly and competently by someone else.
If you are okay running a completely different window in a second STA thread, then that would be the next best thing. That particular window will still be frozen while the document loads, but at least your main UI would still be okay. Note that you should not try to mix and match controls from different threads in the same window; that will lead to all kinds of headaches.
Finally, as a complete hack, you might consider going ahead and calling this Open() method in a background thread in spite of the control being owned by the main UI thread. On the admittedly shaky assumption that the only time that control will actually attempt to access the UI component itself would be at the very end of the Open() method operation, you can go ahead and catch the InvalidOperationException that is thrown, and use that as your signal that the document loading has completed. Then just invalidate the control in the main UI thread.
I'd give the odds of this last suggestion working no better than 50/50. It will depend on what the control actually does with the loaded data, and if it's some kind of composite control where it's relying on actually taking the result of its loading and copying that to a control as part of the Open() method, that part might fail and the control would not wind up properly initialized.
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.
I know there are other questions around this but most end up with the answer don't do what I am about to suggest. So I know you aren't supposed to. The reason for this question is I want to do it anyway, how can I do it...
Here is why I want to break the rules...
Let's say I have a complicated application, it's version 1 and we want our customers to submit errors to us in the event of crashes or hangs. Let's now say I have a button on the top of the main form they click to submit reports.
Let's now imagine that the application hung because of a deadlock...
It would be nice if that small piece of UI and a handler for that button could live on a thread other than the main ui thread so that it isn't caught up in the deadlock. When clicked it would gather all the call stacks for the other threads and submit them to our error reporting service.
Now, knowing the scenario, can this be done in .net?
Yes, there is no magic in creating UI on another thread than the "main thread". The important rule to always keep in mind is to interact with that UI on the thread that created it.
Still, I feel that you are attacking this from the wrong angle. You should probably instead make an effort to push all work off the main thread. That way you minimize the risk for that thread to freeze, and then you don't need to resort to unorthodox solutions for the error reporting.
I have various cases of creating forms on non-main thread, and it works fine every time.
Create a new Thread, and show a Form from it. New message loop will be created for that thread and everything will run fine.
What magic will you use to gather data from the crashed app and locked main thread, that's up to you :)
if application hung, your main message loop is dead, thus ui will not work. As workaround for your problem i'd consider usage of external application (another exe) which will be invoked in case of report
in any case, if you want to invoke UI from other thread you should perform context switch In case of winforms, follow this answer
It sounds like you'd like to keep the UI alive, even when some other operation is mired in a deadlock. If so, perhaps Asynchronous Programming would be of use. Using Async to manage a potentially hung up task would allow the remainder of the application to remain responsive.
we want our customers to submit errors to us in the event of crashes or hangs
You might also consider adding some degree if instrumentation/reporting, so that you'll have this data without requiring user input.
I'm doing all this in C#, in Visual Studio 2008.
I want to slow down the work of my algorithm so that the user can watch it's work. There is a periodic change visible at the GUI so I added Thread.Sleep after every instance.
Problem is that Thread.Sleep, when set to at least a second, after a few instances of Thread.Sleep (after few loops) simply freezes entire GUI and keeps it that way till program completion. Not right away, but it always happens. How soon depends on the length of the sleep.
I have proof that entire program does not freeze, it's working it's thing, even the sleep is making pauses of correct length. But the GUI freezes at certain point until the algorithm ends, at which point it shows the correct final state.
How to solve this issue? Alternative to pausing algorithm at certain point?
First off, don't make the user wait for work that is done before they even think about when it will be finished. Its pointless. Please, just say no.
Second, you're "sleeping" the UI thread. That's why the UI thread is "locking up." The UI thread cannot be blocked; if it is, the UI thread cannot update controls on your forms and respond to system messages. Responding to system messages is an important task of the UI thread; failing to do so makes your application appear locked up to the System. Not a good thing.
If you want to accomplish this (please don't) just create a Timer when you start doing work that, when it Ticks, indicates its time to stop pretending to do work.
Again, please don't do this.
I'd guess everything is running out of a single thread. The user probably invokes this algorithm by clicking on a button, or some such. This is handled by your main thread's message queue. Until this event handler returns, your app's GUI cannot update. It needs the message queue to be pumped on regular basis in order to stay responsive.
Sleeping is almost never a good idea, and definitely not a good idea in the GUI thread. I'm not going to recommend that you continue to use sleep and make your GUI responsive by calling Application.DoEvents.
Instead, you should run this algorithm in a background thread and when it completes it should signal so to the main thread.
You are about to commit some fairly common user interface bloopers:
Don't spam the user with minutiae, she's only interested in the result
Don't force the user to work as fast as you demand
Don't forbid the user to interact with your program when you are busy.
Instead:
Display results in a gadget like a ListBox to allow the user to review results at her pace
Keep a user interface interactive by using threads
Slow down time for your own benefit with a debugger
This depends on a lot of things, so its hard to give a concrete answer from what you've said. Still, here are some matters that might be relevant:
Are you doing this on a UI thread (e.g. the thread the form-button or UI event that triggered the work started on)? If so, it may be better to create a new thread to perform the work.
Why do you sleep at all? If the state related to the ongoing work is available to all relevant threads, can the observer not just observe this without the working thread sleeping? Perhaps the working thread could write an indicator of the current progress to a volatile or locked variable (it must be locked if it's larger than pointer size - e.g. int or an object - but not otherwise. If not locked, then being volatile will prevent cache inconsistency between CPUs, though this may not be a big deal). In this case you could have a forms timer (there are different timers in .Net with different purposes) check the status of that variable and update the UI to reflect the work being done, without the working thread needing to do anything. At most it may be beneficial to Yield() in the working thread on occasion, but its not likely that even this will be needed.