I have a winform application that can catch any number of possible errors. I have found though, that once a messagebox or some other method of displaying the error has been displayed (within a catch block), the program execution continues.
How can I simply stop complete execution of the program in this event and simply just keep the form open? It is only a one form app.
After the message box is displayed, simple call Application.Exit();
This will suffice as long as you don't have any other running threads in the background, but in your case it seems that this is just a simple single threaded application.
You might want to set the owner window of the modal dialog to your form. That way the execution isn't suspended, but the form is deactivated.
Presuming you have something like this:
Private Sub Button1_OnCLick(....) handles button1.onclick
If somecondition then
MsgBox("it failed")
End if
'more code here
and you want to avoid executing 'more code' when the message box has been shown, then add
Exit Sub
just after the MsgBox line
DialogResult result = MessageBox.Show("There was an error, would you like to continue?", "Error",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.No)
{
// Terminate
}
Related
Using Visual Studio 2019, with an old C# Winforms .NET 4.6.2 application: I have a situation where my main form is acting as if it is being blocked by a modal:
Makes a beeping sound and flashes when clicking anywhere
Will not accept focus
Timer and serial communication Events are still triggering
No grey screen overlay, or message about the application ever becoming unresponsive
However, I can see no modal form, and using Application.OpenForms doesn't show any of the modals that I have created and have closed a few seconds previously.
I can successfully attach and debug remotely, that is how I know the timer ticks are still firing.
How / Where can I place a breakpoint to troubleshoot why a form will not receive focus / denies click events / thinks it is being blocked by a modal of some kind?
It is too difficult to create a minimal example because the backgroundWorker and showDialog code all seems to work properly in other locations, but the gist of what is happening looks like:
Application.Run (new FormA)
...
FormA.showDialog(new FormB)
...
FormB.showDialog(new FormC)
...
FormC.timer_tick() { ...still running... }
FormC.onReceive_data() { ...still running... }
FormC.button_click(){
...
showDialog()
...
showDialog()
...
important.showDialog() { backgroundWorker...database stuff }
...
showDialog()
...
}
(known completion : back to FormC event-loop)
It always gets to "known completion" just fine, important.showDialog() seems to work fine, pops up an animating dialog with no buttons, auto closes when backgroundWorker completes, closes itself and moves on to the next dialogs or exits button click fine.
But once back in FormC-Event-loop, the form will not receive any input, as if it is still blocked by some modal somewhere...
If I change to important.show() FormC will not have a problem, but now there is code in the click event running before database activity is finished...
I am more interested in debugging technique in this case as to how I can figure out what windows is doing as I try to click on FormC. What kind of debugging module symbols need to be loaded? Where can I breakpoint to see windows deciding whether a form can receive focus/input?
"something has gone wonky with the re-enabling mechanism" made me go through with a fine tooth comb and check how the dialog is being closed off, and I found the original problem:
FormC starts a backgroundWorker and then waits on important.showDialog()
Inside the RunWorkerCompleted() or a timer_tick : "important" was FormC.BeginInvoke() .closed() and .disposed() . But apparently the .dispose() can (but not always) happen on the wrong thread or at the wrong time and then the parent form can never be enabled again. .close() and nulling the formDialog reference allows the parent to get re-Enabled.
Out of interest, I am still wondering how you would go about debugging such a situation?
I have registered an error handler in my application that shows a user dialog MessageBox when an unhandled exception occurs. It's connected to the Application.DispatcherUnhandledException event and thus happens on the UI thread. Now I've seen a situation where an exception is thrown regularly, once per second, and new dialogs kept popping up. I was trying to prevent this with a lock, but since it's all on the same thread, this doesn't have any effect. An additional sleep lock on the same thread obviously led to a single blocked MessageBox on the screen.
The MessageBox seems to free the UI thread for other MessageBoxes to appear. How can I prevent that without blocking the thread?
The user has the choice to continue or exit the application. When continuing, the next queued MessageBox should appear, it should not be discarded. If too many messages show up in a time, the user can still decide to exit the application.
The problem here is not with the message box. It is that what happens when the message box is still open, while another exception has occurred. In which case, your DispatcherUnhandledException handler gets re-entered on the same thread.
However, the user hasn't made a decision yet about the previous error, the previous message box is still waiting for his input. Your call stack looks like this:
=> DispatcherUnhandledExceptionHandler (current)
MessageBox.Show
DispatcherUnhandledExceptionHandler (previous)
Clearly, you cannot return from DispatcherUnhandledExceptionHandler (previous), without returning from DispatcherUnhandledExceptionHandler (current) first: you're inside a nested call on the same thread. And you cannot return from DispatcherUnhandledExceptionHandler (current) without confirming this fist with the user, back to the egg.
I can think of just one way of solving this, while sticking with your question requirements. It's to display the message box on another thread and block the main thread's message loop while waiting for the user's choice. This way, no more exceptions can occur on the main thread, until you obtain the user's consent regarding the current exception:
Application.Current.DispatcherUnhandledException += (s, e) =>
{
this.IsEnabled = false; // disable the main window
try
{
var result = Task.Factory.StartNew(
() => MessageBox.Show(
e.Exception.Message, "Continue?",
MessageBoxButton.YesNo),
TaskCreationOptions.LongRunning).Result; // this blocks
if (result == MessageBoxResult.Yes)
e.Handled = true;
}
finally
{
this.IsEnabled = true; // enable the main window
}
};
This is ugly from the UI experience prospective, but it gives you the desired workflow.
Message boxes are still windows that run on your thread, so they have to pump window messages (a Modal Message Loop) in order to be repainted when required, moved, handle keyboard input (e.g. Tab to move between controls), mouse input. They still dispatch messages to other windows on the same thread, to ensure that the window that owns them is repainted. The owning window is disabled, so input messages simply result in the default sound being played, but timers will still be fired and any sent or posted messages will still be processed.
The usual source of such problems is that you have a System.Windows.Forms.Timer or WPF DispatcherTimer attached to the window. Other possibilities include background threads using Invoke or BeginInvoke to perform some operation on the UI thread.
Is there any way for detect MessageBox closing. Some workarounds can be possible maybe I can write my own custom MessageBox, but I want the operating system's MessageBox.
Maybe something like MessageBox.Closing += new EventHandler, any suggestions?
There is no "normal" way of doing that, if not using some not very riliable API calls and sniffing. But according to yuor comment, you need may be something like:
var flag = true;
MessageBox.Show(...);
flag = false;
This is a correct way of doing that. MessageBox.Show(...); is a blocking call.
If you need more control, define your own form, and it wil become your message box.
So you can have full control over it, and have also Closing event handler possibility.
You can use the MessageBox found int Extended WPF Toolkit™ Community Edition.
In its documentation there are two events called
CloseButtonClicked
Closed
But as explained in the Tigran answer, the MessageBox.Show call is modal and block the thread in which you make the call, so there is no need to catch the close event unless you are running another thread that should react immediately in some way to the closing of the messagebox.
In my case I just wanted to see if the MessageBox was clicked and then do something, hope it helps.
DialogResult result = MessageBox.Show("Your message");
if (result == DialogResult.OK)
{
Application.Exit(); //whatever you want
}
My program needs to display a dialog box to the user, which prompts the user to select the save folder, and then displays a Yes-No buttons messageBox to ask the user to confirm that they wish to continue.
This is my code:
/* Wait until user has selected a save folder */
do { } while (sSaveFolder == null);
/* Cancel operation if user clicks on cancel when in folder selection window */
if (sSaveFolder == "<cancel>")
{
worker.ReportProgress(0, "Operation Cancelled\r\n\r\n**********\r\n");
return;
}
/* Check for confirmation */
if (MessageBox.Show("Please confirm whether or not to continue.", "Do you wish to continue?", MessageBoxButtons.YesNo) == DialogResult.No)
{
worker.ReportProgress(0, "Operation Cancelled\r\n\r\n**********\r\n");
return;
}
The problem I'm getting is that I can run this once, click No and the worker thread terminates. But, if I click on the button to run the worker thread again, I get the message box popping up at the same time as the save folder dialog box - which, for obvious reasons is problematic. So does anyone know why this might be happening and how to solve it?
I found a work around to my particular problem by moving the message box to before the save folder dialog box but, as this is a weird problem, I thought I'd ask about it crops up again in the future.
Thanks in advance :)
I cannot see anywhere in your code where the value of sSaveFolder would be reset.
Since you are reusing the same object the previous value may still be set, so the do...while completes very quickly and therefore the messagebox is displayed.
Resetting the value of sSaveFolder before you display the dialog should fix your problem.
I'm having a problem with a MessageBox intended to be modal.
Here is the situation,
A user select xx from the form
MessageBox appears
User opens the embebed software keyboard (the built-in one, from the device)
User closes the keyboard
The MessageBox loses focus (how? it's supossed to be modal!) and the main form is shown in the foreground
The app blocks, as the user cannot now close the MessageBox.
Here is the code snippet for the MessageBox.
MessageBox.Show("message", "caption", MessageBoxButtons.OK, MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button1);
Any ideas on how to solve this?
This is actually somewhat expected behavior under Windows CE (I'm not saying it's right, just expected).
When you click on the SIP button down in the corner of the desktop, your entire app loses focus and focus is passed to the Task Bar. You can see similar "wierdness" by clicking on your application's Task Bar button - the MessageBox will lose focus, even though by all rights you should just be sending focus to the app that is already running.
You can see that it's not a CF bug by changing your MessageBox call like so:
private void button1_Click(object sender, EventArgs e)
{
//MessageBox.Show("message", "caption", MessageBoxButtons.OK,
// MessageBoxIcon.Asterisk,
// MessageBoxDefaultButton.Button1);
MessageBoxCE(this.Handle, "message", "caption", 0);
}
// renamed to not collide with the Windows.Forms MessageBox class
[DllImport("coredll", EntryPoint="MessageBox")]
private static extern int MessageBoxCE(IntPtr hWnd, string lpText,
string lpCaption, int Type);
And you get the exact same behavior.
The one thing that is not expected is that the parent Form is coming up above the MessageBox. I just tested on an ARM-based CE 5.0 device I have on my desktop and the MessageBox stays on top in both the CF and the P/Invoke versions.
Are you able to repro this behavior with a very basic app (i.e. just one form, one button)? If so then it sounds like a platform issue. One thing to remember about using CE is that since the OEM has a lot of control over how the OS is actually implemented, you can never rule out a platform bug for behaviors.
You need to include a reference to the parent form when calling the MessageBox.Show (the IWin32Window parameter, usually just pass in "this"). I believe this is the overload you want to use - see below:
MessageBox.Show Method (IWin32Window, String, String, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton)
Here is a link to the Microsoft documentation.
Enjoy!
MessageBox.Show("Please insert Correct Username and Password.", "Login Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
this.Focus();
Its a simple solution. no need to run any JavaScript or other C# Code.