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
Related
This question already has answers here:
How to prevent clicks outside the current form?
(2 answers)
Closed 1 year ago.
I am creating an application where I have a Form 1 (Main Form). Inside this main form there is a button that opens up a different and smaller form (Form 2). I don't want to hide Form 1 when showing Form 2 but because of the size of Form 2, the user is able to click Form 1 hiding Form 2 with its size (not hidden like Form2.hide();) however this is something I don't want to do. I want to prohibit the user to click Form 1 if Form 2 is currently open. Is there any event or function I can use to do this? I have seen in it in other applications but I don't even know how to look for it.
In addition to using the ShowDialog method as suggested in question's comments, you can disable the form itself if you want for example the user be able to switch between forms and view or copy some text.
Form.ShowDialog Method: Shows the form as a modal dialog box.
Here is a definition:
Wikipedia: A modal window creates a mode that disables the main window but keeps it visible, with the modal window as a child window in front of it. Users must interact with the modal window before they can return to the parent application. This avoids interrupting the workflow on the main window. Modal windows are sometimes called heavy windows or modal dialogs because they often display a dialog box.
If you don't want to use a modal form, you can initialize the form2 instance like that:
form2.FormClosed += (_s, _e) => this.Enabled = true;
Thus now you can call:
this.Enabled = false;
form2.Show();
You can also check the ShowInTaskBar property of the form2.
Be careful not to add the lambda event handler several times to the same instance: if form2 is just hidden on close, only one FormClosed += is needed, but is required for every instance of a form you want to manage this way.
If you need to disable only certain controls, use them instead of this:
private void SetControlsEnabled(bool state)
{
myControl1.Enabled = state;
myControl2.Enabled = state;
myPanelHavingSomeControls = state; // this changes all inners too
...
}
form2.FormClosed += (_s, _e) => SetControlsEnabled(true);
SetControlsEnabled(false);
form2.Show();
This is the exact use case for a modal form, which disables the parent form and provides visual clues from the OS to tell the user of that relationship. Something along the lines of this will do:
//Code in the event handler that opens the child form
using (Form2 childForm = new Form2())
{
//Put any initialization code here
childForm.ShowDialog(this);
//Any cleanup or using some return value from the form after it closed
}
In the form calling the 2nd form I have this code:
this.WindowState = FormWindowState.Minimized;
frmCalledForm frm = new frmCalledForm();
frm.Show();
this.WindowState = FormWindowState.Normal;
And in the Load() event of frmCalledForm
this.TopMost = true;
this.BringToFront();
this.Activate();
I have the code calling the 2nd form in a button click event and at one point I open it programmatically based on certain conditions.
In both cases, the called form does not get focus, the calling form retains focus, even though it is minimized and then returned to normal.
I found the above code in this SO question, and apparently it's working for him, but for some reason it's not working for me.
Due to Chris's comment about returning the calling form to Normal state, I commented that line out, but left the line minimizing the calling form.
Besides the fact that, to the user, the main form will suddenly disappear to his taskbar and stay there, which obviously doesn't make for a good user experience. But when I ran the program with the modified code, the main form went to the taskbar, and the called form opened, but still did not have focus. I was quite surprised to see that.
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.
I have a problem with modality of the forms under C#.NET. Let's say I have main form #0 (see the image below). This form represents main application form, where user can perform various operations. However, from time to time, there is a need to open additional non-modal form to perform additional main application functionality supporting tasks. Let's say this is form #1 in the image. On this #1 form there might be opened few additional modal forms on top of each other (#2 form in the image), and at the end, there is a progress dialog showing a long operation progress and status, which might take from few minutes up to few hours. The problem is that the main form #0 is not responsive until you close all modal forms (#2 in the image). I need that the main form #0 would be operational in this situation. However, if you open a non-modal form in form #2, you can operate with both modal #2 form and newly created non modal form. I need the same behavior between the main form #0 and form #1 with all its child forms. Is it possible? Or am I doing something wrong? Maybe there is some kind of workaround, I really would not like to change all ShowDialog calls to Show...
Image http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png
Modal forms do exactly what "modal" means, they disable all other windows in the app. That's rather important, your program is in a somewhat perilous state. You've got a chunk of code that is waiting for the dialog to close. Really Bad Things could happen if those other windows were not disabled. Like the user could start the modal dialog again, now your code is nested twice. Or she could close the owner window of the dialog, now it suddenly disappears.
These are the exact kind of problems you'd run into if you call Application.DoEvents() inside a loop. Which is one way to get a form to behave modal without disabling other windows. For example:
Form2 mDialog;
private void button1_Click(object sender, EventArgs e) {
mDialog = new Form2();
mDialog.FormClosed += (o, ea) => mDialog = null;
mDialog.Show(this);
while (mDialog != null) Application.DoEvents();
}
This is dangerous.
It is certainly best to use modal forms the way they were designed to stay out of trouble. If you don't want a modal form then simply don't make it modal, use the Show() method. Subscribe to its FormClosing event to know that it is about to close:
private void button1_Click(object sender, EventArgs e) {
var frm = new Form2();
frm.FormClosing += new FormClosingEventHandler(frm_FormClosing);
frm.Show();
}
void frm_FormClosing(object sender, FormClosingEventArgs e) {
var frm = sender as Form2;
// Do something with <frm>
//...
}
The first thing that comes to mind would be something like this. You could disable form 1 when you launch form 2 and then have form 1 handle the closed event of the second form to re-enable itself. You would NOT open modal 2 using show dialog.
Now keep in mind, from a user perspective this is going to be quite cumbersome, you might look at doing a MDI application to get all windows inside of a single container.
Your main form will not be responsive until any modal dialogs that are in the same process space are closed. There is not work around for that.
It looks to me like you could use an MDI application setting the Form #0 IsMdiContainer property to true.
Then, you could do something alike:
public partial class Form0 {
public Form0 {
InitializeComponent();
this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened.
}
private void button1_Click(object sender, EventArgs e) {
Form1 newForm1 = new Form1();
newForm1.Parent = this;
newForm1.Show();
}
}
Using the ShowDialog() as you stated in your question will make all of the forms Modal = true.
By definition, a modal form is:
When a form is displayed modally, no input (keyboard or mouse click) can occur except to objects on the modal form. The program must hide or close a modal form (usually in response to some user action) before input to another form can occur. Forms that are displayed modally are typically used as dialog boxes in an application.
You can use this property [(Modal)] to determine whether a form that you have obtained from a method or property has been displayed modally.
So, a modal form shall be used only when you require immediate assistance/interaction from the user. Using modal forms otherwise makes believe that you're perhaps running into a wrong direction.
If you do not want your main form to be an MDI container, then perhaps using multithreading is one solution through a simple BackgroundWorker class is the key to what you want to achieve. Thus, it looks to me like a design smell...
What is it you want to do, apart of making your main form responsive, etc.
What is it you have to do?
Explaining what you have to do, we might be able to guide you altogether into the right, or at least perhaps better, direction.
Actually the answer is very simple. Try
newForm.showDialog();
This will open a new form, while the parent one is inaccessible.
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.