I launch a thread via ThreadPool.QueueUserWorkItem which has a messagebox dialogue in it:
System.Windows.Forms.DialogResult dr = System.Windows.Forms.MessageBox.Show("would you like to download upgrade in background? ..", "Upgrade Available", MessageBoxButtons.YesNo);
It seems to work fine however I am a little suspicious after some customers suggested they were not getting the message popping up. I had the feeling in .NET framework 2.0+ you do not need to marshal this particular call, it does it for you. Correct?
This is a semi-related topic for interest:
Why use a owner window in MessageBox.Show?
No, it doesn't Marshal to the UI thread. If you think about it, it wouldn't be possible for it to do so.
It's possible to have more than one UI thread in an application. Some programs, such as internet explorer, have many UI threads. Which UI thread would the .Show call pick?
It's also possible to use MessageBox.Show in an application that has no UI threads. You can very well call this in a Console application and it will work.
MessageBox.Show will show UI on the thread it is called from. If there isn't already a message pump running on the thread it will setup a temporary one in order to function. It will tear it down after the Show call completes.
As a general rule, you shouldn't do GUI work outside of the main/application thread. I'd make a ShowMessageBox method on the parent form that can do an Invoke:
public DialogResult ShowMessageBox (String message, String caption)
{
if (this.InvokeRequired) {
return (DialogResult) this.Invoke (new PassStringStringReturnDialogResultDelegate (ShowMessageBox), message, caption);
}
return MessageBox.Show (this, message, caption);
}
public delegate DialogResult PassStringStringReturnDialogResultDelegate (String s1, String s2);
BUT ALSO KEEP IN MIND: when debugging a multi-threaded GUI app, and you're debugging in a thread other than the main/application thread, YOU NEED TO TURN OFF the "Enable property evaluation and other implicit function calls" option, or else VS will automatically fetch the values of local/global GUI objects FROM THE CURRENT THREAD, which will cause your application to crash/fail in strange ways. Go to Tools->Options->Debugging to turn that setting off.
Sorry for the caps, but this took me DAYS to figure out why I every time I tried debugging my app it would hang and then crash.
Well, I would marshal and specify a window, if only so the MessageBox can get the correct focus. It might be they simply can't see it because it is behind one of your forms, and doesn't know it should be in the foreground.
Is this an application or a service. If it's a service, maybe it's not set up with the 'Allow interaction with desktop' permission.
See the properties of the service in the services control panel applet.
Related
First, what I need is - n WebBrowser-s, each in its own window doing its own job. The user should be able to see them all, or just one of them (or none), and to execute commands on each one. There is a main form, without a browser, this one contains control panel for my application.
The key feautre is, each browser logs on to secured web page and it needs to stay logged in as long as possible. Well, I've done it, but I'm afraid something is wrong with my approach.
The question is:
Is code below valid, or rather a nasty hack which can cause problems:
internal class SessionList : List<Session> {
public SessionList(Server main) {
MyRecords.ForEach(record => {
var st = new System.Threading.Thread((data) => {
var s = new Session(main, data as MyRecord);
this.Add(s);
Application.Run(s);
Application.ExitThread();
});
st.SetApartmentState(System.Threading.ApartmentState.STA);
st.Start(record);
});
}
// some other uninteresting methods here...
}
What's going on here? Session inherits from Form, so it creates a form, puts WebBrowser into it, and has methods to operate on websites. WebBrowser requires to be run in STA thread, so we provide one for each browser. The most interesting part of it is Application.Run(s). It makes the newly created forms alive and interactive. The next Application.ExitThread() is called after browser window is closed and its controls disposed. Main application stays alive to perform the rest of the cleanup job.
When user select "Exit" or "Shutdown" option - first the browser threads are ended, so Application.ExitThread() is called. It all works, but everywhere I can read about "main GUI thread" - and here - I've created many GUI threads. I handle communication between main form and my new forms (sessions) with thread-safe methods using Invoke(). It all works, so is it right or is it wrong?
Is everything right with using Application.Run() more than once in one application? :) An ugly hack or a normal practice? This code dies if I start a WebBrowser from the session form thread. It beats me why. It works however if I start WebBrowser (by changing its Url property) from any other thread. I'd like to know more what is really happening in such application. But most of all - I'd like to know if my idea of "applications in application" is OK.
I'm not sure what exactly does Application.Run() do. Without it forms created in new threads were dead unresponsive. How is it possible I can call Application.Run() many times? It seems to do exactly what it should, but it seems a little undocumented feature to me. I'm almost sure, that the crashes are caused by WebBrowser component itself (since it's not completely "managed" and "native"). But maybe it's something else.
Is everything right with using Application.Run() more than once in one application? :) An ugly hack or a normal practice?
Some of both ;) This is perfectly acceptable, in that it will function as you are expecting, but it's not exactly a "normal practice."
I'm not sure what exactly does Application.Run() do.
Application.Run basically does a couple of things. First, it installs the property SynchronizationContext into the thread for Windows Forms to run properly. It then starts the windows message processing in that thread, which processes all messages from Windows going into the thread. This is what allows forms to work properly.
There's nothing particularly wrong with doing this, but it isn't a standard practice. Given your design goals, I do question whether this would be better served by just launching a separate process instead of trying to run each operation within a separate thread.
I'm using the following code to open a new form (that is for user input) in my function:
Form4 f4 = new Form4();
f4.mainform = this;
f4.get_Text(matchString);
f4.ShowDialog();
It's working perfectly when not threading, but when I try to run the function on two threads I only get 1 form popup. How can I adjust it so that it will support more than one thread?
You can open a form from any thread, you just need to start a message loop on the new thread, such as:
Application.Run(f4)
The Run method will not return until the form is closed. It can cause issues, though, so you need to be careful and know what you are doing. Unless it's a real pain to do, I would sooner consider redesigning your code to be more asynchronous. For instance, you could create a event handler method to listen for the form's closing event.
The WIN32 Message pump runs on one thread -- the GUI thread. As soon as you .ShowDialog(), the c# stops until the user closes the dialog. Even if you use .Show() to avoid a "stop and wait for the user to push ok", you still must handle all GUI events on the GUI thread by .Invoke()ing to the GUI thread.
The way to support multi-threaded-ness is by doing non-GUI work on alternate threads.
ShowDialog does pump messages so it would technically work on a separate thread without needing a dedicated message loop. However, what you currently have looks like a recipe for disaster because that form appears to hold a reference to another form via f4.mainform = this and it is presumably trying to access it. You simply cannot do this without littering (and I mean that literally) your code with a bunch of Invoke or BeginInvoke calls.
Furthermore, running UI forms on a thread other than the main UI thread generally does not work well. There are a few obscure problems you can run into. For example, since there would be two UI threads in play it is possible to have 2 active modal dialog boxes open. One might be hidden behind the other and the end user would not see it. This reason, among others, is why it is not generally recommended to use more than one UI thread.
My advice is to figure out a way to make this work with a single UI thread. Your life will be simplier if you do.
Some of our non-technical users are having problems where a dialog MessageBox in our application can sometimes be displayed behind the main form and the application does not accept any input until the messagebox (which they can't see) is dismissed.
The application is written in C# and the message boxes are standard eg the code can be as simple as MessageBox.Show(message, caption) and the messageboxes can be created by the main UI thread (ie not some background thread). The Application does not have to be run full-screen, but 90% of our users do run it full-screen.
Most of the time ((maybe > 99%) the messageboxes display correctly and I have never managed to see how it goes wrong, but I have seen a machine when it has gone wrong.
One thing I did notice is that if you have an application which displays a dialog box, then when you look at your taskmanager, you normal only see one entry in the application list. Whenever the messagebox is hidden, you will see two entries, one for the main application and another entry for this message box.
It is easy enough to fix the problem once you know what has happened, but some of our non-technical users are confused by it and end up switching off their computers. (And the ones who are using Remote Desktop are even more confused when that doesn't solve the problem).
I do not think it is related to the operating system as I have seen it happen in Vista and have been told it also happens in a terminal session on a Windows 2003 server.
Does anything know why this is happening and more importantly if anything can be done to avoid it?
Some overloads of the MessageBox.Show() method take an IWin32Window parameter as the first argument. If you pass in your Form as that first argument it should prevent this from happening.
Is it always the same message box (for the same message?) coming the same form?
Ideally, you should try to find some way to reproduce the problem at will, or at least automatically. This will make your debugging easier and you can then be sure that your future change will have fixed the bug, rather than have to wait for a few weeks for the feedback from your users.
If it is always the same message and in the same window, resulting from the same action, and if the MessageBox call is reasonably easy to trigger from an user point-of-view and if your UI is relatively standard, you could automate the UI with an AutoIT script and have it run in a loop until the problem happens.
And/or, you could create a "debug"-build of your applications that you could give it to some users (preferably the ones that seem to run into the problem the most often) that would write the contents of a StackFrame object to a log file or something similar everytime before calling a MessageBox (you could create a wrapper around the MessageBox to make this easier).
Then, when one of your users gets the problem, you can look at the log file and see where it came from (source code file, line, calls stack etc). You could also compare this to the logs from other users and see if, everytime, the MessageBox comes from the same location or if it varies.
This would show you where the problematic MessageBox is called from and where.
There may be easier solutions (especially if your application has a lot of assemblies) involving some .Net debugger that you would attach to your application when the problem occurs in order to see the call stack, etc, but I only did this with native applications (using OllyDbg) so far and not .Net. Others may be able to expand further on this idea...
Confirm the problem. What we do to fix it is following:
Run new Task and display the message box
In the main UI thread while task is still running - wait in the loop that does DoEvents. Something like this
UPDATED 2015-12-17.
Reproduced problem yestarday. To repo in my case - minimize the app, "wait" popup occures (in our case it happens after some idle time), then in the task bar click on the main app icon. This "hides" the popup so it is not possible to bring it on the screen. The code below was tested and solves the problem. But I still do not understand what/why it happens.
private static DialogResult ShowMessageBox(
string message,
string caption,
MessageBoxButtons buttons,
MessageBoxIcon icon)
{
var showMessageBoxTask = new Task<DialogResult>(() =>
{
var form = new Form() {TopMost = true};
var result = MessageBox.Show(
form,
PrepareMessage(message),
caption,
buttons,
icon);
form.Dispose();
return result;
});
showMessageBoxTask.Start();
while (!showMessageBoxTask.IsCompleted && !showMessageBoxTask.IsFaulted)
{
Application.DoEvents();
}
return showMessageBoxTask.Result;
}
You say "the messageboxes can be created by the main UI thread", which I assume means they aren't always created by the main UI thread. Your problem sounds like MessageBox.Show is occasionally called from another thread.
In the parent form, add this before MessageBox.Show():
this.TopMost = false;
My application (C#, VS2008) loads information from a database (SQL Server 2008 Express) over the network. During (possibly) longish waits, I want to have a 'Loading...' dialog box appear running on a different thread, but only if the operation takes more than a specific time period (say 500ms).
So, I have so far got my loading form being displayed after 500ms (if the operation lasts that long) without setting the loading dialog form's owner (i.e calling LoadingDialog.ShowDialog()), but when I try to call LoadingDialog.ShowDialog(IWin32Window owner) with owner set to the main form (passed in through the thread's parameter) I get the InvalidOperationException about accessing controls across threads.
My basic question is: Can I create and ShowDialog a form with the owner parameter set to a form on another thread? I want to do this so that the loading dialog is modal the rest of the application, i.e. like any other dialog takes the focus and disallows input elsewhere.
Can anyone offer a suggestion? I have read heaps about splash screens with no luck, also about Invoke and BeginInvoke with no luck. Is there a different way I should go about this?
Please feel free to ask for clarification if you don't understand.
Merci (as they say in French),
Jacob.
You should run your long process in a background thread, and then show your Loading... form as a non-modal dialog. That way, the user can see the Loading indication, but still interact with other parts of the system while its going on.
Another option would be to show the loading progress in a status bar or similar. The key is to make sure the long operation is done on a background thread and all the GUI logic is done on the GUI thread.
A good threading format might look like (this is just pseudocode for demonstration purposes - you need to use Invoke to get the appropriate threading):
RunInBackground(DoLongOperation);
ShowLoadingDialog();
...
DoLongOperation()
{
LongOperation();
RunOnGUI(FinishLongOperation);
}
FinishLongOperation()
{
CloseLoadingDialog();
}
All the UI components run on single sole thread which runs over the win32 message loop. You can not run any UI component in another thread. This architecture persists since Windows 3.1.
You CAN create as many UI threads as you want. The following code should do the trick:
Thread thread = new Thread(new ThreadStart(() => Application.Run(new MyForm())));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
I'm building a UI for a program, and I can't figure out why my progress bar won't become visible after the convert button is clicked.
private void convertButton_Click(object sender, EventArgs e)
{
toolStripProgressBar.Visible = true;
...
toolStripProgressBar.Visible = false;
}
I ran into a similar problem with tkinter in Python, and I had to call a function to update the idle tasks. Is there a way to do this with windows forms without using threads?
Edit: On a side note, this is a progress bar in a toolStrip that also contains a label that gets updated with status bar text. Is there any way to get the label on the left side and the progress bar on the other instead of right next to each other on the left?
Well, there is a way to do this without using threads (Application.DoEvents) but I strongly recommend against you using it. Re-entrancy is nasty, and you really don't want the UI thread tied up at all.
Use BackgroundWorker instead - it's easy, and it's pretty much designed for progress bars. It takes the hassle out of using a separate thread and reporting progress back to the UI thread. No need for Control.Invoke etc - it takes care of that for you.
There are lots of tutorials for BackgroundWorker - it shouldn't take you too long to get going with it.
Per the question you asked for the way to do this WITHOUT threads, that is to do it with Application.DoEvents();. (Just add that call right after setting the progress bar as visible.)
Now I do agree with Jon Skeet though that BackgroundWorker is a better way of doing this, but it does use a separate thread.
You need to execute your process in a thread separate from the UI thread, and then have it periodically report back to the UI thread with it's progress. If your convert operation is working inside the UI thread, it will simply go unresponsive until the operation is complete.
The progress bar can only become visible when it is allowed to paint which occurs during the processing of messages. Message processing cannot normally happen while you are in the middle of an event handler. If you want the progress bar to show up you will have to set the visiblitity to true, start a background thread to complete the work and return from the handler.
I'm guessing the problem is that the "..." in your code is a long-running process. UI updates are not instantaneous, but must run through the message queue in windows and then be painted to the screen. The queue is pumped and painting takes place in the same thread as your events.
As a result, any long-running tasks need to be moved to a different thread. More than that, your line line of code needs to called after that thread terminates. Otherwise you set the progress bar and then immediately turn it off again.
One way to do that is with a BackgroundWorker control.
Here go two links trying to explain you how things work:
(1) (2)
Now, I will try to explain it as shortly as I can. Most of what happens inside a windows forms application happens in a single thread, usually the same thread Main() runs in. If you open Program.cs, you will see that Main() has a line that looks like the following:
Application.Run(new Form1());
If you debug the application at any moment and examine the call stack, you will see it will trace back to that Run method. This means that a Windows Forms application is in fact a continuous run of the Run method. So, what is Run doing? Run is eating a message queue through which Windows sends messages to it. Run then dispatches those messages to the correct controls, which themselves do things like add text which corresponds to the key being pressed, redraw themselves, etc. Notice that all this happens during and endless loop running alongside a single thread, so weather you are typing or simply moving the window around, loads of those messages are being passed onto the application, which in turn is processing them and reacting accordingly, all in that single thread. Controls can also send messages to themselves through the queue and even you can place messages in the pump via Control.BeginInvoke. One of the things those controls do is to raise events according to what happens. So, if you click a button, the code you've written to handle that click will ultimately and indirectly be run by the Application.Run method.
Now, what is happening with your code is that even though you are changing the visible status of your progress bar to visible and then updating its Value, you are then changing its visibility to false, all in the same method. This means that only after you leave the method, will Application.Run() be able to continue iterating and consuming the message queue, effectively asking the progress bar to update its display. When that happens, you've already left the progress bar's visibility to false, the last thing you did before exiting the method. DoEvents() is a quick and dirty workaround to your problem as it reads the messages in the queue and processes them. I don't really feel comfortable using it as it can bring reentrancy problems.
Using threads is a good solution, but I would recommend using a ThreadPool thread instead of a custom thread in this kind of situation, as I tend to use custom threads only in cases where I have a limited number of long lived threads and I need to control their life cycles. The easiest and most practical way to use threads is to use the BackgroundWorker component, even though I would recommend going through the pains of understanding how to do Windows Forms multithreading with delegates if you want to really understand what is going on.
My solution is to call refresh on the status strip.
I believe this causes the UI thread to repaint the status strip.
toolStripStatusBar1.PerformStep();
statusStrip1.Refresh();
This is for .NET 4.0. Even though this question is old it was the first I found on googling this issue.