This question already has answers here:
How do I prevent the app from terminating when I close the startup form?
(4 answers)
Closed 7 years ago.
well, i did a multi forms app in c#. This means that i had more forms including one which is the main menu. All forms has ,among others,a button which return to the main menu.(Except from the main menu form which has buttons which access a specific form)
Well this is how i make this transition.
this.Close();
Form1 Myform1 = new Form1()
Myform1.Show();
The problem is that when i randomly close the app, it dissapear , as i want,but it doesn't close completely.I mean it only dissappeared, but it still runs.
WHY? and HOW TO DO IT TO CLOSE ENTIRELY ?
The basic problem you are running into is that by default, your Winforms program will exit when the main form (the one that is displayed first) is closed. This is because the reference to this form is passed to the Application.Run(Form) method in the program's Main() method.
There are a variety of ways to deal with the issue, but IMHO the most straightforward is to not close the form. Instead, call the Hide() method on your main form. This will cause it simply to not be shown, but not closed. When you want to return to it, just call Show() on that form instance and it will be visible again.
Naturally, to accomplish this you will need to pass that reference to any other code that may want to use it. So you may wind up for example with code that looks like this:
this.Hide(); // Not Close()!
Form1 Myform1 = new Form1(this)
Myform1.Show();
Then somewhere in the Form1 class, where you are ready to close that and show the main form again, you would call the Show() method. That might look something like this:
partial class Form1 : Form
{
private readonly MainForm _mainForm;
public Form1(MainForm mainForm)
{
_mainForm = mainForm;
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
_mainForm.Show();
}
}
Another way to handle this is to just not have the MainForm passed to the Application.Run() method in the first place. Instead, call the parameterless overload of Application.Run(). But then you will need some other mechanism for closing the program. For example, calling Application.Exit() at the appropriate time.
While this seems to me to very a fairly common question, I was unable to find another question that seemed like an exact duplicate. However, there are definitely a large number of other related questions, including the following:
C# Application.Run without Form
Close a windows form without exiting the entire application
How can I close a login form and show the main form without my application closing?
If I close one of my forms, they all close
Methods this.hide() vs this.close()
Those last two are particularly relevant, but unfortunately the top answer in each is probably the worst way to solve the problem (i.e. put each form into its own thread…one should use multiple UI threads as a last resort only, and doing so is definitely not called for here). So take any advice you read in any of the above questions with a grain of salt. There is some good information among the answers, but there is also a fair amount of bad advice as well.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
In my Windows form the application doesn't exit even though I execute this.Close();
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
If I try disposing it directly it just crashes.
In my main class I open an instance, which is what i'm trying to close. Before it didnt't want to close, it didn't open.
This is not my main class.
FIX: Replacing "show()" with "showDialog()" fixed it.
Remarks from Form.Close()
When a form is closed, all resources created within the object are
closed and the form is disposed. You can prevent the closing of a form
at run time by handling the Closing event and setting the Cancel
property of the CancelEventArgs passed as a parameter to your event
handler. If the form you are closing is the startup form of your
application, your application ends.
The two conditions when a form is not disposed on Close is when (1) it
is part of a multiple-document interface (MDI) application, and the
form is not visible; and (2) you have displayed the form using
ShowDialog. In these cases, you will need to call Dispose manually to
mark all of the form's controls for garbage collection. NoteNote
When the Close method is called on a Form displayed as a modeless
window, you cannot call the Show method to make the form visible,
because the form's resources have already been released. To hide a
form and then make it visible, use the Control.Hide method. Caution
noteCaution
Prior to the .NET Framework 2.0, the Form.Closed and Form.Closing
events are not raised when the Application.Exit method is called to
exit your application. If you have validation code in either of these
events that must be executed, you should call the Form.Close method
for each open form individually before calling the Exit method.
This clearly states that the form should close and application should end unless you do something else we cannot see in your example.
The Close method is a Form's method, it closes the Form, this closes the Application instead :
// Close everything down.
Application.Exit();
As you can see the Application Class doesn't have a Close method, it has an Exit method instead, the this.Close() closes the concerned Form, but keeps the application running.
I have a C# WinForms application running on .NET Framework 4.0.
When the user is inactive for a certain period of time, I want it to hide all the displayed forms and show an icon in the notification area. When the user clicks that icon, a login form appears and if the credentials are valid, it opens the exact forms that were open before.
To do this, I store the list of open forms in a List of Form objects and hide them, like this. This method is called by a Timer:
private void LogOut()
{
foreach (Form form in Application.OpenForms)
if (form.Visible)
{
GlobalVariables.formList.Add(form);
form.Hide();
}
}
When the credentials are validated, I try to make the forms visible again, like this:
//Show the previous forms.
foreach (Form form in GlobalVariables.formList)
form.Visible = true;
//Clear the forms list.
GlobalVariables.formList.Clear();
If I only have the MainForm open when I hide the forms, it shows it back fine when logging back in. If I have any other forms open (which are opened using ShowDialog() from the MainForm), the program will crash on form.Visible = true; and give me the following error message:
ObjectDisposedException was unhandled
Cannot access a disposed object
How can I fix this problem? An alternative way of doing what I'm trying to achieve would also be great.
Please note that using a try - catch block to determine if the form has been disposed and just relaunch the form is not an option as the user may have unsaved input in the hidden forms.
I couldn't manage to find anything related online in over 3 hours of search so any help would be much appreciated!
EDIT: After trying various things, I have noted that the problem only occurs on forms I have opened forms using ShowDialog(). If I only have forms opened using Show(), everything works fine.
However in my case, using Show() is not an option because I cannot have the user click on things in the parent form. Hiding the parent form is not an option either as he needs to see information in the parent form.
Clearly hiding a form is more impactful than you counted on. Your code was involved in a security review that Microsoft conducted on Winforms. Very thorough, not often visible in the way it behaves but very visible in the source code. One rule is imposes is that a user should never lose control over the application.
A dialog is very troublesome that way. The core problem is that ShowDialog() creates a modal window that disables all the other windows. That creates an opportunity for malware, very easy to take advantage of, all it has to do is hide a dialog and you snookered the user. There isn't any way that the user can gain control of the app again. The one window that was enabled is hidden with no way for the user to re-activate it again. All the other windows are disabled so trying to click on them, or their taskbar button, will not have any effect. All that's left is for the user to use Task Manager to kill the app. And if the user account is locked down then that's not an option either.
I can hear you sputter by now: "But, but, it is my code that hides the dialog, not malware!" That's not the way it works in Windows, there's no way to tell that it actually was your code that did it. Not only because it could be injected code, it doesn't even have to be code that runs in your process. Any code can do it, it is part of the winapi.
So there's a specific counter-measure against this built into Winforms, it will automatically close a form if it is hidden while operating in dialog mode. Which of course has a big impact, code that was written after the ShowDialog() call will now run. Anything is possible, but a sure-fire mishap in your case is that this disposes another window and an attempt to revive it will die.
The rough guidance here is that you are doing it wrong. You are trying to build a security system on top of one that's already highly secure and heavily tested. And it is very risky, handling passwords yourself is a very good way to make the overall system much less secure. The average user will of course favor picking the same password as he used to login to Windows. Makes it much easier for an attacker to harvest that password.
Call LockWorkStation() instead.
After many hours of trial and error, I found out what the problem was.
My understanding of modal forms was that code would continue executing in the parent form only after the modal form was closed. In fact, the specification found on MSDN states:
A modal form or dialog box must be closed or hidden before you can continue working with the rest of the application.
This introduced a subtle bug in the way I handled the forms. This is the code I used to display the forms:
using (var theForm = new CreateInvoice())
{
theForm.ShowDialog();
if (theForm.Updated)
{
GetInvoiceStatus();
}
}
The using statement disposes of theForm as soon as the statement exits. Normally, this works perfectly fine as it would be called only when the user closes theForm. However, because ShowDialog() permits the parent form to continue its work when it is hidden, this meant that the code actually exited the using statement, which effectively disposed of theForm, resulting in my error.
Testing, it seems that Hide()ing a modal dialog - closes it. It actually triggers the FormClosing event.
Tested like this: (Also, see this answer.)
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
Hide();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
MessageBox.Show("Closing");
}
EDIT
I noticed this actually doesn't solve the mystery, just adds more information. Here's another piece of information: When you're setting Visible to true - you're not showing it modal again. This time it's equivalent to Show().
One suggestion to the design: instead of saving forms(views), you should save the data that the form holds(Model) and destroy the form. When you need the form again, create it back with the data(model). First, this can resolve this mysterious dispose problem, second, each form will need GDI resource, which are limited, if two many forms, you'll encounter the memory and GDI problems.
As how to do this, please refer the MVC or MVP design pattern.
BTW my guess on this problem: when you make the form visible, it will try find its parent, but its parent may be already disposed. I encountered this problem once, it throws the object disposed exception.
how to open form 1 on close button click X in form 2
i tried this but it is not working:
private void supplierShow_FormClosing(object sender, EventArgs e)
{
new suppliersList().Show();
}
Thank you.
Not fully sure without knowing more your code but to me it looks like you are declaring a local variable (new suppliersList of base class Form probably) and showing the form from the Closing event of another form.
Your Form2 object is probably going to be deleted/disposed/garbage collected soon and at that point I am not completely sure that the form declared within that scope would still have a nice life.
If Form2 is the application form, the application will actually terminate when you close it.
in general I think that this kind of form switching is best done and controlled from the main method, the same place where you probably have Application.Run(new Form2()); because in there you have full control of the application flow and MessageLoops...
I have to solutions:
First:
You may have a unique reference to your suppliersList in Program class:
public static suppliersList SuppList = new suppliersList();
you can now hide it if you want:
Program.SuppList.Hide();
you can show it anytime, too:
Program.SuppList.Show();
Be carefull! Don't Dispose SuppList. If you did, assign to it a new object new suppliersList();. Please note that this solution would success only if form1 is not the main form (i.e. Application.Run(new form1()); )
Second:
You can start form2 as a child of window of form1:
new suppliersList().Show(this);
because, as in the other answer, the application loops are on form1. If form1 is closed, then entire application will be closed too. However, starting a child window of the main window will prevent application close.
If the answer is useful for you, please mark it as your best answer.
In C#, I'm trying to get two forms (but probably three eventually) to start at the same time... I've tried adding a new "Application.Run" to my Program.cs file, but it only starts the second form after the first one closes.
So how could I create something like that? Similar to a program like Lazarus.
You simply have to show your form before invoking Application.Run().
var form1 = new Form1();
var form2 = new Form2();
form1.Show();
form2.Show();
Application.Run();
Word of warning here, since no form is tied to the Application.Run call, you will need a way to tell the application to exit when all your forms are closed.
To display a Form you have 2 methods:
Show() - display a non modal dialog (is what you want); also you need to add Application.Run for to work.
ShowDialog() - display a modal(some blocking) dialog; a modal dialog capture all the input for the current thread.
If you want a interface like Lazarus, google by the "MDI application".
I think you probably should decide on one form to be your "primary" form, and then have the other form(s) be member variables of your main form. Then just have the Load event of your primary form also show the secondary form(s).
so,
class MainForm : Form {
readonly Form _otherForm = new OtherForm();
override OnLoad(EventArgs args) {
_otherForm.Closed += // add a handler for what happens when otherForm is closed.
_otherForm.Show();
base.OnLoad(args);
}
}
There may be a better way of doing this but that's what I would do as a first shot.
In my application I want to show a login form first and then the main form if the login has been successful. Currently I'm doing it something like this:
var A = new LoginForm();
if ( A.ShowDialog() == DialogResult.OK )
Application.Run(new MainForm());
But then I started wondering - what's the point of the Application.Run()? Why not just do (new MainForm()).ShowDialog() as well? What's the difference? And what would be the correct way to achieve what I want?
Application.Run(Form) starts a message loop on the current thread and displays the specified form. The message loop enables the form to receive Windows messages (eg, key presses, mouse clicks, paint invalidations) to allow it to appear responsive and have interaction with the user. When you call ShowDialog() on a Form instance, it actually does a similar thing and creates a modal message loop for the form on which ShowDialog has been called.
There is not much difference between the two calls. Application.Run does add some extra event handling enabling you to do some tidying up of resources when the main form is closed (see Application.ThreadExit).
The recommended way to start WinForms applications is using Application.Run, but I suspect this is more of a convention than a rule. The biggest reason to use Application.Run is if you want to open multiple non-modal forms. You can do this using:
new Form().Show();
new Form().Show();
Application.Run();
You could not achieve this using the ShowDialog() method as one of the forms would have to be modal.
As for your question of how to show a login form and then the main form if the login is successful, I think what you have is fine:
if (new LoginForm().ShowDialog() == DialogResult.OK)
{
Application.Run(new MainForm());
}
The alternative is to do the plumbing yourself and open an instance of MainForm in the closing event of the LoginForm if the login was successful.
From MSDN:
This method adds an event handler to
the mainForm parameter for the Closed
event. The event handler calls
ExitThread to clean up the
application.
http://msdn.microsoft.com/en-us/library/ms157902.aspx
From my testing, I noticed this main difference:
When Application.Run is used, the form's Close button (red X) returns DialogResult.None; however, when ShowDialog is used, the Close button produces DialogResult.Cancel.
Does this matter to you? In my code, I was testing for DialogResult.Cancel to determine the exit code of my application. That was broken when the red X was used to close the form. I now test for DialogResult.OK to indicate a successful exit.
return myForm.DialogResult == DialogResult.OK ? 0 : 1;
One key difference is that ShowDialog is usually a modal Dialog. If you wanted to create a user-friendly toolset, you would not want it to be comprised of modal dialog boxes.
Also, Application.Run() accepts more than just a form. It has a few overloads.
As for your application, I do not think it matters much. Application.Run makes sense to me because it denotes the start of your actual Application.
The documentation of the overload
public static void Run(
ApplicationContext context );
has a neat example with a different approach that involves two forms as well.
For a more concerete example of a difference:
If your main form is an MDI form, then the behavior on clicking the close button (the 'x' in the upper right, or Alt-F4) is different depending on which method you use to show the form.
With Application.Run(mainForm), the closing event of the child forms run, then the main form's closing event runs.
With mainForm.ShowDialog, the closing event of the main form runs, and the closing event of the child forms do not run.
Application.Run() is for the start of application while MainForm is part of the application and MainForm()).ShowDialog() used to display it only.
Application.Run() is the entry point for your Application. same as Main() method is for some class or ApplicationStart() for a WebApplication
Application.Run() has different overloads, one of which is without parameters. That Method starts application without an initial form.
From my testing I notice that using Application.Run buttons with DialogResult does not close the form (OnFormClosing is not hit) compare to ShowDialog in which the buttons with DialogResult hit OnFormClosing and the close the form.