Show modal loading window in Winforms for long-running process - c#

I would like to show a wait gif, while verifying a file and this is what I have tried so far.
There is a form - Form1, where user clicks a button to verify a file, and there is another form - Wait, with just a picturebox showing a gif image.
button_click()
{
Wait wait = new Wait();
wait.ShowDialog();
VerifyFile();
wait.Close();
}
The Wait form does show up, but it doesn't close. Also, the verification is also not done. It continues only when I manually close the Wait form.
How to auto close the wait form, once VerifyFile() is complete.

The problem with your code is that Form.ShowDialog() method is synchronous and it waits for the result from the "Form" dialog. This means that the code execution is hold up untill the "wait" dialog will be closed.
Consider moving the VerifyFile() method into Wait dialog:
class Wait: Form
{
public Wait() : base()
{
System.Threading.Tasks.Task.Factory.StartNew(() => VerifyFile());
}
}
You can close this dialog when after VerifyFile execute's over.

Related

How to properly wait for input from modeless window

I have an application that has two mode-less windows. The first window, has a button to take input from the other window. My question is what is (is there?) the right way to call the second window for input and block the caller until user provides an input inside the text box. Here is a visual of what I'm trying to explain here:
App starts. Main window opens
User clicks on first button in main window -> second "modeless" window opens. User switches back to main window
User clicks on second button in the main window -> second "modeless" window is activated and focused
Second window now waits for input into the text box. This is where the question is: How to block the call from the main window, wait for input in the textbox, and return to caller only when user has entered input into the textbox, while not freezing the windows
I have this sudo-code as the solution for now but the loop is happening inside the main app code and it uses too much cpu just looping. Not sure if there is a better/right way to do this in C# and WPF specifically:
// input control mechanism
private object _inputLock = new object();
private bool _waiting = false;
// public string ReadInput() method starts waiting
do {
// pass control to dispatcher to update ui
inputTb.Dispatcher.Invoke(
() => { },
System.Windows.Threading.DispatcherPriority.Background
);
lock (_inputLock) {
if (!_waiting)
break;
}
} while (true);
// input text box handler turns off waiting
private void SendInput() {
lock (_inputLock) {
_waiting = false;
}
}

Why Form.Close wait MessageBox.Show?

look this please:
var form = new Form();
form.Shown += (_, __) =>
{
var timer = new System.Windows.Forms.Timer { Interval = 1000 };
timer.Tick += (x, xx) =>
{
timer.Stop();
GC.KeepAlive(timer);
timer.Dispose();
form.Close();
Application.DoEvents(); // no effect
// it will cause form keep show
MessageBox.Show("asdf");
// but if this, that's fine
// BeginInvoke(new Action(() => MessageBox.Show("asdf")));
};
timer.Start();
};
form.ShowDialog();
form.Close before MessageBox.Show, but form will not close until close msgBox, please help.
--end--
all in code, why need more words? all in code, why need more words? all in code, why need more words?
When you show a form as modal using ShowDialog(), calling Close in fact sends a WM_CLOSE message and then it sets DialogResult to Cancel which acts as a flag for modal message loop to exit the loop.
So Close will not close or hide the modal dialog immediately. Then after finishing the modal message loop, the modal dialog will be hide (but not destroyed).
MessageBox method also blocks the execution of code, so codes after the message box will execute just after closing the message box. So now it's clear why after calling Close, first the MessageBox shows then after closing message box, form closes.
Just to make it easier to understand, here is a pseudo-code which shows what is happening when you call ShowDialog in your code:
Form Shows
While Form.DialogResult != None
{
Form.Close → Sends WM_CLOSE → Sets Form.DialogResult = Cancel
MessageBox.Show and wait until MessageBox closes
}
Form Hides
Just keep in mind, Close is not equal to return, it means the code which you have after Close will run as well. Here the code is MessageBox which blocks the loop until after MessageBox closes.
To hide the dialog immediately, replace the form.Close() with form.Hide(), this way without waiting for the loop, you are commanding the form to get hidden. But it doesn't mean the form has been closed and therefore lines of code which you have after ShowDialog will not run until after the loop finishes.
For more information about how Close and ShowDialog work, you may want to take a look at a Windows Forms source code, specially the following lines:
LocalModalMessageLoop in Application
CheckCloseDialog in Form
WMClose in Form

Modeless form doesn't receive the input focus

I have a Windows Form ("form1") which is opened with ShowDialog() in the main thread of application just before Application.Run() is called ( without that form as the argument ). From the main thread another thread ("thread2") is created, which runs in parallel with the main thread. With pressing a button in the "form1", another form ("form2") is created in the "thread2" and shown with Show() method. The problem: the "form2" doesn't get the input focus and doesn't receive keyboard or mouse input.
The form2 is created as follows:
public form2( )
{
InitializeComponent();
this.WindowState = FormWindowState.Normal;
this.TopMost = true;
this.SetStyle( ControlStyles.Selectable, true );
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Bounds = Screen.PrimaryScreen.Bounds;
}
I created a handler on OnFocusLosing event which writes a string to the console, and see that the form2 is losing focus just after creation. Is it the form1, which is opened with ShowDialog() and runs in the main thread grabs the focus back? I tried to minimize the form1 before creating the form2, but it doesn't help.
How one can get a form to receive the input focus?
As far as I know there is only ever a single UI thread in a Windows Forms application, you can't just spawn off threads and expect the user to be able to interact with them.
You could try this if you really need two independent UI threads: https://social.msdn.microsoft.com/Forums/en-US/3f0e7794-8671-47c4-aa9a-3bd1f85c9963/how-to-create-a-winform-app-with-two-ui-threads

MessageBox shown before form closes

Why is the messagebox shown before the form closes?
SomeForm myForm = new SomeForm();
myForm.Show();
MessageBox.Show("Some text");
Do I need to start a new thread, and wait for it to finish? I've never come across this problem before.
You need to use Form.ShowDialog() instead. Form.Show shows a modeless window, whereas Form.ShowDialog shows a modal form, i.e., that the user has to close before continuing.
Your example never actually closes myForm...only shows it. I would expect the code above to show myForm and then immediately show the MessageBox.
If you want myForm to close before showing the MessageBox, you'll need to call myForm.Close() at some point.
The reason for this is that myForm.Show(); starts the opening of a new window, however it is not a blocking call. It's not a dialog, it's a separate window, which runs on it's own.
If you want SomeForm to show as a Dialog (blocking window, waits for close to continue execution), then use ShowDialog. If you want to wait till the window is opened before you show the MessageBox, then add the MessageBox to the OnLoaded on the SomeForm claa.
If it's important that the user not be able to interact with the main form while this other form is being shown then you can use myForm.ShowDialog instead of Show. ShowDialog is a blocking function, so it won't return until the other form is closed. Show, on the other hand, just shows the other form and then immediately returns without waiting for the form to be closed.
If it's intentional that the other form is not being shown modally, and you don't (or can't) make that change, then you can use events to show a message box when the other form is closed.
SomeForm myForm = new SomeForm();
myForm.FormClosed += (form, args) =>
{
MessageBox.Show("Some text");
};
myForm.Show();
This will add an event handler, which fires when the other form is closed, and executes the desired code at the appropriate time.

C#/.NET: how do I close the application from a parent window?

I have a Windows application that has 2 Forms. From one form I am opening a 2nd form.
When opening the 2nd form I am hiding 1 form and in the second foem I am starting a thread.
Now I want to close the application.
But I was not able to do that.
On my 1st form I have tried:
Form1 frm = new Form1(this, tcpClient);
frm.ShowDialog();
this.Close();
Application.Exit();
But the application is not ending. It still running.
Any idea how to stop that?
EDIT (CODE Included):
On 1st form's button click event:
this.Hide();
Form1 frm = new Form1(this, tcpClient, serverMsg);
frm.Show();
On 1st form's button FormClosed event:
MessageBox.Show("Before");
Application.Exit();
On 2nd form's load event I am calling a method startThread(); on this method
ilThread = new Thread(incomingListener);
ilThread.IsBackground = true;
ilThread.Start();
When you do frm.ShowDialog() you're opening a modal window. The code will stop at that point until you specify a DialogResult on frm. I.e. frm.DialogResult = DialogResult.Ok;.
If you use frm.Show() that might work for you.
Edit- See #GenericTypeTea's answer first. If after doing that you are still having issues see mine:
From what you describe it sounds like you have left the thread running. Have you tried creating the thread as a background thread or making sure you end that thread in a clean way?
You probably didn't set the Thread you started as a background thread. Background threads are stopped automatically when application closes. Foreground threads will keep it alive.
To set thread as background thread use IsBackground property.
See Thread.IsBackground.
Otherwise you should take care yourself of stopping the started thread before exiting the application.

Categories

Resources