Cannot access a disposed object - c#

My program has multiple forms. The fifth and final form has a button that when clicked closes the application using the method Application.Exit(). However every time I click the button I receive the error 'cannot access a disposed object' surrounding this code on my first form:
frm2 f2 = new frm2();
this.Hide();
f2.ShowDialog();
this.Show();
The compiler indicates that the statement this.show() is the problem. Could someone explain why I am receiving this error and how to fix it?

Ok edited my answer, I reproduced your issue. If you want to use Form.ShowDialog then you should set the DialogResult of the control that is closing the application. So in the buttons properties you should set the dialog result to something, for example Cancel.
Then on the buttons click event you would do something like this:
private void btnClose_Click(object sender, EventArgs e)
{
if (this.DialogResult == DialogResult.Cancel)
{
Application.Exit();
}
}
Otherwise if you don't need to use Form.ShowDialog, you can just show Form2. The above does not produce the error in my testing.

In your code example, did frm2 make a call to Application.Exit? If it did, then why are you trying to call this.Show again?
Anyway, you may have a problem related to how you started the application's message loop. Are you running Application.Run(), or Application.Run(form1)?
If you provided a form to Application.Run() when you started your message loop, then you should not be calling Application.Exit in order to exit the application. Instead, you should simply close your main window, that would cause the message loop to finish, the call to Application.Run to return, and your application will terminate cleanly.

Related

Visual Studio c# DialogResult doesn't seem to work

I'm using visual studio 2010
frmMain has a "Register" button which calls another form newReg
This is the code for the button in frmMain that calls the second form. The problem is that the MessageBox("So Far So Good") never gets called. The dialogResult doesnt seem to be recognized.
private void btnRegisterNew_Click(object sender, EventArgs e)
{
// newReg Constructor Call
newReg = new frmRegisterNew();
// show form
newReg.Show();
if (newReg.DialogResult.Equals(DialogResult.OK))
{
MessageBox.Show ("So Far So Good");
}
}
The second form has some fields to fill in and a button "register". I've set the dialogResult of this button to 'ok' in the properties window and also, I think, in the code. When the "register" button in the second form is clicked it checks the input, tries to update a database and closes if successful. Here is that bit of code:
dbConnection db = new dbConnection();
db.dbConnect();
if (db.dbRegisterVehicle(txtNewReg.Text, txtNewMake.Text, txtNewModel.Text, txtNewColour.Text, OwnerID))
{
// if insert worked close
this.DialogResult = DialogResult.OK;
this.Close();
}
db.dbDisconnect();
I'm sure what to try, or what I might be over looking.
Use ShowDialog
newReg = new frmRegisterNew();
var dialogResult = newReg.ShowDialog();
if(dialogResult==DialogResult.OK)
{
....
}
The ShowDialog method is a good way to go but be aware of the differences between Show and ShowDialog. The latter will be modal which means that you can't access your original form until the new form is closed. This is why it blocks the check and may or may not be what you want.
When you call Show, it doesn't block, so that's why your code was immediately checking to see if the DialogResult was equal to OK (it wasn't equal to OK because your new form had barely opened by the time the check was made).
The alternative to using ShowDialog, if you want to use Show, is to handle the new form's closed event.
frmRegisterNew newReg = new frmRegisterNew();
newReg.FormClosed += (s, o) =>
{
if (newReg.DialogResult == DialogResult.OK)
{
MessageBox.Show ("So Far So Good");
}
};
newReg.Show();
This means that your code will continue to work and your new form will not be modal, but when the new form it closed, the FormClosed event handler will be fired. Don't worry if you're not familiar with the event handler notation above (they're called anonymous methods) but you can still use the event handler as normal.
newReg.FormClosed += new FormClosedEventHandler(newReg_FormClosed);
void newReg_FormClosed(object sender, FormClosedEventArgs e)
{
MessageBox.Show ("So Far So Good");
}
Try instantiating the DialogResult class and using it this way:
DialogResult dr = new DialogResult();
newReg = new frmRegisterNew();
dr = frmResgisterNew.ShowDialog();
if ( dr == DialogResult.OK )
//Take an action here.
Form.Show() is non-blocking and will return very quickly. Your check on newReg.DialogResult.Equals(DialogResult.OK)) will therefore occur before the user has had a chance to press the button. Furthermore, note this warning about closing the window:
If a Form is displayed as a modeless window, the value returned by the DialogResult property might not return a value assigned to the form because the form's resources are automatically released when the form is closed.
(via the Form.DialogResult Property msdn library page)
You can either call From.ShowDialog() or, if you need to keep interaction on the main form, pass a delegate for the other form to call when it's completed.
Edit: A couple of points to keep in mind:
In addition to the warning above about closing the form, you have to be careful about trying to access the contents from a method dispatched from newReg's message loop (including the function that called Close()) after it's been disposed.
If you end up using ShowDialog() instead of Show(), however, this.Close() will not dispose the form. In fact, it essentially does nothing since setting DialogResult to anything other than None will automatically hide the form. If you need deterministic clean-up (presumably why you're calling Close() in the first place), you should call newReg.Dispose() after you're done with it in btnRegisterNew_Click. Otherwise, the form will be disposed at some unpredictable time in the future (provided your application doesn't end abnormally in the interim).
If you use an anonymous function as mentioned by keyboardP, be aware that it can get hard to debug when something goes wrong (especially if you're relatively new to the language and framework).

How to force close button to terminate all childforms?

I have program that opens subwindows inside of it (mdi.parent). I have made component that is in one window under it, however, i want that that window never actually disposed after its created because i want to keep only one instance of it.
This can be made with code:
// This prevents this window disposing from window close button, we want always show one and only
// one instance of this window.
FormClosing += (o, e) =>
{
Hide();
e.Cancel = true;
};
However, after this there is problem, closing program requires pressing close button press twice. First press closes subwindow and second terminates program. How this can be get around?
I am working with Winforms.
As Habib said, you can call Application.Exit, but:
The Form.Closed and Form.Closing events are not raised when the
Application.Exit method is called to exit your application
If this is important to you, you can do something like this (MDI parent code):
private Boolean terminating;
protected override void OnClosing(CancelEventArgs e)
{
if (!terminating)
{
terminating = true;
Close();
}
base.OnClosing(e);
}
Call Application.Exit() in the form close event.
Application.Exit - MSDN
Informs all message pumps that they must terminate, and then closes
all application windows after the messages have been processed.
The code inside of your FormClosing event handler method is a bit too terse. It does its job of preventing the user from closing the form, but as you've also noticed, it prevents you from closing the form programmatically as well.
This is easily solved by testing the value of the CloseReason property of the FormClosingEventArgs that are passed in each time the event is raised.
These will tell you the reason why the form is attempting to close. If the value is CloseReason.UserClosing, then you want to set e.Cancel to true and hide the form. If the value is something else, then you want to allow the form to continue closing.
// This prevents this window disposing when its close button is clicked by the
// user; we want always show one and only one instance of this window.
// But we still want to be able to close the form programmatically.
FormClosing += (o, e) =>
{
if (e.CloseReason == CloseReason.UserClosing)
{
Hide();
e.Cancel = true;
}
};
Use This
Form[] ch = this.MdiChildren;
foreach (Form chfrm in ch)
chfrm.Close();
You can use Application.Exit if there is no processing happening when the application is closed. Otherwise, you can check Application.OpenForms collection in MDI parent's closing event and close all the other forms that are open.

FolderBrowserDialog not showing up on second form

Ok, this is the main essence of what I am trying to achieve and the symptoms of what it is doing.
I have a main windows form. On this form the user can click on a button that will open up a new and seperate form. This form will have a button that is supposed to display a FolderBrowserDialog. Instead it simply locks up form2 and never displays anything.
Here is essentially the code I have dealing with the form etc.
This is in the first form that is loaded after i do some uninteresting things.
FORM1.cs
//do stuff
//In a button.click method I do the following
Application.Run(new Form2(myParameters1, 2, 3));
This is the second form that is called from the first form
FORM2.cs
//do more stuff with the parameters on load
//user clicks on a button
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.RootFolder = Environment.SpecialFolder.Desktop;
fbd.Description = "This is the browser dialog box";
if(fbd.ShowDialog() == DialogResult.OK)
{
//do stuff
}
}
After I click on the button the dialog box does not show up and the form2 gets locked from doing anything.
I have also attempted changing the
fbd.ShowDialog()
To
fbd.ShowDialog(Form2.ActiveForm)
with the same results.
Any help would be appreciated! If you need more info let me know and I can try to provide all that I can.
EDIT
I forgot to mention (and actually completely forgot) That the method that opens up the second form is a seperate thread.
So the first form starts a thread, which opens the second form, which is supposed to open a dialog which it is not. Now i think it has to do with the threading..
I have figured out my issue. It ended up being that the thread from Form1 that was opening Form2 was not able to open DialogBoxes because it was seperate from the UI thread entirely.
I ended up working around using that thread and just eliminated it completely which solved my problem. The dialog box opened up just as I wanted.
Thank you all for the responses though! They did help me figure out a few other things I failed to do correctly.
I had similar problem. Main GUI thread was creating a backgroundworker thread to write to database but when background thread is failed used to show a custom control dialog to save exception file. THis custom dialog was shown correctly however Browse button on it to open folderBrowserDialog to save the exception file wouldn't show. My custom control would show "Not Responding" in its title bar.
What I did was instead of calling Custom Control directly I made it call on UI thread itself
like this.
void DBThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
this.Invoke(new CrossThreadExceptionHandler(CatchInterThreadException), e.Error);
}
}

To close C# Forms Application

I have 2 forms ...when i start the application..and use the close "X" from the title bar the entire application closes...now when i select an option from the 1st form in my case it is a button "ADD" as its a phonebook application..it goes to the 2nd form as i have used 1stform.hide() and 2ndform.show()...now when i do "X" from the title bar it doesnt shutdown completely as the 1stform is not closed....how to program it in such a way tht any stage the entire application should close
Your first form is set as the startup form. That means whenever it gets closed, your entire application is closed. And conversely, your application does not close until it gets closed. So when you hide the startup form and show the second form, the user closing the second form does not trigger your application closing because they have only closed a secondary, non-modal dialog.
I recommend changing your design so that the startup form is also the main form of your application. No sense trying to work around built-in functionality that can actually be useful. You want the application to quit when the main form is closed, no matter what other child forms are opened.
But the quick-and-dirty solution in your case is to make a call to Application.Exit. That will close all of the currently open forms and quit your application immediately. As I said just above, I don't so much recommend this approach because having to call Application.Exit from every form's FormClosed event handler is a sign that something has gone seriously wrong in your design.
If the single startup form paradigm doesn't work out for you, you should look into taking matters into your own hands and customizing the Main method in your Program.cs source file. See the answers given to this related question for some ideas on how that might work for you.
What you can do is to use the Form's FormClosing event, and add the following code:
Application.Exit();
This will stop the entire application, and close all windows. However, if a background thread is running, the process itself will survive. In this case you can use:
Environment.Exit();
Add a Application.Exit on every forms's Closing event
like this:
Create an closing event handler first
private void Form_ClosingEventhandler()(object sender, CancelEventArgs e)
{
//Perform any processing if required like saving user settings or cleaning resources
Application.Exit();
}
then bind this event to any form you create.
//Where you create new form and show it.
Form1 frm= new Form1();
//set other properties
frm.Closing += new EventHandler(Form_ClosingEventhandler);
Form2 frm2= new Form2();
//set other properties
frm2.Closing += new EventHandler(Form_ClosingEventhandler);
Surely you don't want to shut down the entire application after the user adds a phone number? You just need to make sure that your main window becomes visible again. Write that like this:
private void AddButton_Click(object sender, EventArgs e) {
var frm = new AddPhoneNumber();
frm.StartPosition = FormStartPosition.Manual;
frm.Location = this.Location;
frm.Size = this.Size; // optional
frm.FormClosing += delegate { this.Show(); };
frm.Show();
this.Hide();
}

Why won't Application.Exit() quit a Windows Forms application?

I am working on learning Windows Forms with C# and have a bare bones application. I am trying to close it when the user selects File->Exit. I have an event handler attached to it and I have tried calling Application.Exit(), Application.ExitThread() and just closing the form. Nothing. It stays there. I'm not creating any other threads of any sort either.
Ideas? Thanks.
Have you tried to put a breakpoint in the event handler to see if it is being hit?
If so, the application won't exit if the window messages aren't being delivered (i.e. the UI thread is blocked). One way to test this is to call Environment.Exit() which is more brutal about forcing a close. If this succeeds, you can then figure out why Application.Exit() isn't working.
Application.Exit isn't the normal way to close a GUI application. Use form.Close instead.
private static void OnMenuClose_Click(object sender, System.EventArgs e)
{
Form dlg = ((Control) sender).FindForm();
//dlg.DialogResult = DialogResult.OK;
dlg.Close();
}

Categories