FormClosing event cancel from within another event? - c#

For a school project, I have been asked to create a web browser.
In the context menu I have an "Exit" button, which does a bunch of stuff like uploading data to an SQL database etc. If there is an error in the "try" block, the catch block offers the user a question if he wants to close or not.
In the "formclosing" event, I have connected my already existing "exit" functionality from the "exit" button, so that if the user presses the red "X" (on the window screen) to close the form it will have the same effect.
The problem is that because it's a "formclosing" event, it closes the form even if the user chose "no" in the question dialogue from the "Exit" button.
So my question is how do I cancel the "formclosing" request from within my "Exit" button?
P.S.
Please ignore strange things like the delete sql command, our teacher has some strange requests. Assume that that is indeed the requested functionality.
private void יציאהToolStripMenuItem_Click(object sender, EventArgs e)
{
Favorite fav;
SqlCommand delfav = new SqlCommand("DELETE FROM tblFavorites", conn);
SqlCommand addfav = new SqlCommand("INSERT INTO tblFavorites VALUES (#title, #url)", conn);
addfav.Parameters.Add("#title", SqlDbType.NVarChar, 100);
addfav.Parameters.Add("#url", SqlDbType.NVarChar, 300);
try
{
conn.Open();
delfav.ExecuteNonQuery();
for (int i=0; i<favorites.Items.Count; i++)
{
fav = (Favorite)favorites.Items[i];
addfav.Parameters["#title"].Value = fav.getsettitle;
addfav.Parameters["#url"].Value = fav.getseturl;
addfav.ExecuteNonQuery();
}
Application.Exit();
}
catch
{
DialogResult dialogResult = MessageBox.Show("There was a problem loading your favorites to the database. Do you still wish to quit? \n (All changes to the favorites list will be lost)", "", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
Application.Exit();
}
else
{
//Cancel the formclosing event here!
}
}
finally
{
conn.Close();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
יציאהToolStripMenuItem_Click(null, null);
}

You should replace the functionalities for these two event handler. Also you should use this.Close() instead of Application.Exit()
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// your code
try
{
// your code
}
catch
{
DialogResult dialogResult = MessageBox.Show("There was a problem loading your favorites to the database. Do you still wish to quit? \n (All changes to the favorites list will be lost)", "", MessageBoxButtons.YesNo);
if (dialogResult != DialogResult.Yes)
{
//Cancel the formclosing event here!
e.Cancel = true;
}
}
finally
{
conn.Close();
}
}

Related

Check for changes on a windows form before closing

This should be an easy google search but I can't find the answer.
When I click the close button on my form I want to check and warn the user if information on the form has changed. For this my code is adequate.
But if the user clicks the X button on the top of the form no check is performed.
So I tried using the "FormClosing" event to execute the same code below but it goes into some weird loop, I think because i have used this.close which also triggers the same FormClosing event.
What is the correct way to check for form changes when either a button or the X is clicked.
private void buttonClose_Click(object sender, EventArgs e)
{
// Close the form and warn if record not saved
//Check for unsaved changes
if (formDataChanged == true)
{
DialogResult dr = new DialogResult();
dr = MessageBox.Show("Data on this form has changed, Click OK to discard changes", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
if (dr == DialogResult.OK)
{
this.Close();
}
}
else
{
this.Close();
}
}
Update
I think the linked example may be too simple?
When I looked at the CloseReason I received the same results when I closed the window either way so I'm not sure how I can use this to trigger different results.
CloseReason = UserClosing
Cancel = False
private void FormTelephoneLog_FormClosing(object sender, FormClosingEventArgs e)
{
System.Text.StringBuilder messageBoxCS = new System.Text.StringBuilder();
messageBoxCS.AppendFormat("{0} = {1}", "CloseReason", e.CloseReason);
messageBoxCS.AppendLine();
messageBoxCS.AppendFormat("{0} = {1}", "Cancel", e.Cancel);
messageBoxCS.AppendLine();
MessageBox.Show(messageBoxCS.ToString(), "FormClosing Event");
}
I tried adding a bool variable as was also suggested in the other post but it still loops. I know why because the this.close() command also triggers FormClosing event but I still can't figure out how I should do this correctly.
I see there are 6 possible scenarios.
No changes, Close Button -> Works
No changes, X Button -> Loops
Discard changes, Close Button -> Works
Discard changes, X Button -> Loops
Don't Discard changes, Close Button -> Works
Don't Discard changes, X button -> Fails ***
*** The form is still closed and the changes are discarded.
Here is the code as it is now. I'm going round and round including more and more conditions. This would seem like a very common thing to want to do. I'm missing something obvious.
private void buttonClose_Click(object sender, EventArgs e)
{
CloseButtonClicked = true;
checkFormChanges();
CloseButtonClicked = false;
}
private void FormTelephoneLog_FormClosing(object sender, FormClosingEventArgs e)
{
if (CloseButtonClicked == false)
{
checkFormChanges();
}
}
private void checkFormChanges()
{
// Close the form and warn if record not saved
//Check for unsaved changes
if (formDataChanged == true)
{
DialogResult dr = new DialogResult();
dr = MessageBox.Show("Data on this form has changed, Click OK to discard changes", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
if (dr == DialogResult.OK)
{
formDataChanged = false;
this.Close();
}
}
else
{
this.Close();
}
}
Update 2
I just kept adding conditions until all the possibilities worked.
I think it is a confusing solution but it works.
Working Code
private void buttonClose_Click(object sender, EventArgs e)
{
closeButtonClicked = true;
checkSaveChanges();
closeButtonClicked = false;
}
private void FormTelephoneLog_FormClosing(object sender, FormClosingEventArgs e)
{
if (closeButtonClicked == false)
{
if (formDataChanged == true)
{
checkSaveChanges();
}
e.Cancel = closeCancelled;
closeCancelled = false;
}
}
private void checkSaveChanges()
{
// Close the form and warn if record not saved
//Check for unsaved changes
if (formDataChanged == true)
{
DialogResult dr = new DialogResult();
dr = MessageBox.Show("Data on this form has changed, Click OK to discard changes", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
if (dr == DialogResult.OK)
{
formDataChanged = false;
this.Close();
}
else
{
closeCancelled = true;
}
}
else
{
this.Close();
}
}
One does not tell a closing form to close. You either let it close or cancel it, that's all there is to it.
Calling this.Close() will warp space-time around itself, cause an infinite loop, and annoy a certain Time lord. Pray that you don't get a Q, they're a bunch of pricks.
Here's an example:
bool UnsavedChanges; // Some bool your controls set true during change events.
// Set it false after saving and after loading things
// ie.: in a RichTextBox when loading a file, so doesn't count as a "change".
void FormClosingEvent(object sender, FormClosingEventArgs e) {
if (UnsavedChanges) {
var result = MessageBox.Show("You have unsaved changes!", "Quit without saving?", MessageBoxButtons.YesNo);
if (result == DialogResult.No) {
e.Cancel = true;
}
}
}
You were thinking too hard.
I ended up figuring it out.
Seems like an ugly solution to me but it works.
See Update 2 in my question above.

Cancel form closing

I'm writing a WinForm desktop application. In the main form, the user clicks on a button which calls another form for the user to submit data to. At the end of this submission process, the user clicks on a "Save" menu item to close the subform.
This is the code for the subform calling:
private void btnSubmit_Click(object sender, EventArgs e)
{
// code for setting myFormArgs
myForm form = new myForm(myFormArgs);
form.ShowDialog();
// the user clicked "Yes" on a "Confirm" MessageBox
if (form.DialogResult == DialogResult.Yes)
{
// code for saving data
form.Dispose();
}
}
and this is the code for the "Save" menu item in the subform:
private void menuSave_Click(object sender, EventArgs e)
{
string message, title;
MessageBoxIcon icon;
MessageBoxButtons buttons;
if(DataSubmitted)
{
if(ValidData)
{
message = "Confirm?";
title = "Select an action";
icon = MessageBoxIcon.Information;
buttons = MessageBoxButtons.YesNo;
}
else
{
message = "Incomplete data";
title = "Error";
icon = MessageBoxIcon.Error;
buttons = MessageBoxButtons.OK;
}
}
else
{
message = "No data submitted";
title = "Error";
icon = MessageBoxIcon.Error;
buttons = MessageBoxButtons.OK;
}
this.DialogResult = MessageBox.Show(message, title, buttons, icon);
if (this.DialogResult == DialogResult.Yes) this.Close();
else this.OnFormClosing(new FormClosingEventArgs(CloseReason.None, true));
}
The problem is that the code will always get back to the calling method, thus closing (maybe just hiding?) the sub-form, even if the this.Close() method isn't called.
Thanks in advance.
you should not make a new event instance, those are things you would want to avoid
instead try:
DialogResult dialogResult = MessageBox.Show("Sure", "Some Title",
MessageBoxButtons.YesNo);
if(dialogResult == DialogResult.Yes)
{
Close();
}
Events are supposed to occur automatically, so 'OnFormClosing' will raise when the form will close.
also i recommend to use this.Close instead of Dispose
Form.Close() sends the proper Windows messages to shut down the win32 window. During that process, if the form was not shown modally, Dispose is called on the form. Disposing the form frees up the unmanaged resources that the form is holding onto.
for more organized code,
try making an instance of the form from the main form
and handle the dialog result like this:
using (SubForm form = new SubForm())
{
DialogResult dr = form.ShowDialog();
if(dr == DialogResult.Yes)
{
string studdToSave= form.StuffToSave;
SaveToFile(studdToSave);
}
}
I find it strange that you want to close the form when the user just wants to save the data. :)
Save should not close your form.
When you close the form, you should verify if there are unsaved changes.
If there are, ask the user the question if he wants to save his changes before closing and offer him the options Yes, No and Cancel, where Cancel means 'cancel closing the form'.
Depending on wether the user clicked Yes or No, you should or shouldn't save the changes.
If the user clicked cancel, you should cancel closing the form by having an event for the FormClosing event. This event allows you to cancel closing the form.
private void btnClose_Click(object sender, EventArgs e)
{
if (unsavedChanges)
{
var result = MessageBox.Show("Save changes?", "unsaved changes", MessageBoxButtons.YesNoCancel);
if (result == DialogResult.Yes)
{
SaveChanges();
}
if (result == DialogResult.Cancel)
{
cancelClose = true;
}
this.Close();
}
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = cancelClose;
cancelClose = false;
}
The code above is usefull when 'Form2' is not a modal form.
If you want Form2 to be shown modal, the code above will work as well. However, you can also use the DialogResult proprety of the Form in that case:
private void btnClose_Click(object sender, EventArgs e)
{
if (unsavedChanges)
{
var result = MessageBox.Show("Save changes?", "unsaved changes", MessageBoxButtons.YesNoCancel);
if (result == DialogResult.Yes)
{
SaveChanges();
}
if (result == DialogResult.Cancel)
{
result = DialogResult.None;
}
this.DialogResult = result;
}
}

Validating user's input before continuing program execution

I have created a program that contains (for now) 2 forms.
In the first form I am asking the user for a file. After the user has selected a file, another form is called followed by closing of the current form.
An if statement indicates if the user has inserted a file when the Open File button is pressed, and if not, the second form will not be loaded.
The problem is that if the user clicks the Close button on the first form (the current one), the form closes and the next one is called.
The options of the next form are based on the user's input in the first form (where the user is asked to select a file), so if the second form is called when the user cancels the first form, it will create problems for methods in the second form.
Any ideas about how to handle the Close Button?
If you want to prevent closing the form you can handle the event
bool cancel = true;
protected override void OnFormClosing(FormClosingEventArgs e)
{
e.Cancel = cancel;
base.OnFormClosing(e);
}
Remember to change cancel to false when it's done to close the form.
There is an event named "FormClosing" on forms.
A quick sample:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Are you sure you want to quit?", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
}
I am assuming that you have an OpenfileDialog (to allow the user to select a file),and a button probably named Open File to pass the filename to next form.If this is the case,then you can try to to disable the open button if no file has been selected.
Consider the code below as the function where all logic takes place;
private void BrowseFile()
{
//dlgopenfile is the name of Openfiledialog that allows the user to browse for a file.
//string filename is the name of selected file if any.
//Form2 is the next form.
try
{
switch (dlgopenfile.ShowDialog())
{
case DialogResult.OK://If Ok(Yes) button is pressed on Openfiledialog.
filename = dlgopenfile.FileName;
break;
case DialogResult.Cancel://If Cancel button is pressed on Openfiledialog.
filename = "";
break;
}
if (filename.Length >= 1)
{
if (File.Exists(filename) == true)
{
ButtonOpenFile.Enabled = true;
}
else
{
ButtonOpenFile.Enabled = false;
throw new FileNotFoundException("The file you selected does not exist.");
}
}
}
catch (FileNotFoundException ex)
{
MessageBox.Show(ex.Message, "Form1", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
The next function occurs if user tries to close the form in mid session.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
switch (MessageBox.Show("Do you want to exit ?", "Form1", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk))
{
case DialogResult.Yes:
this.Close();
break;
case DialogResult.No:
e.Cancel = true;
break;
}
}
catch (Exception)
{
//Exception handling code goes here.
}
}
Finally the function below calls Form2's constructor with the selected file as argument.
private void ButtonOpenFile_Click(object sender, EventArgs e)
{
//This Button is enabled only if the file has been selected and if its exists.
Form2 form2 = new Form2(filename);//filename is the name of selected file,as decided in function BrowseFile().
this.Close();//Close Form1.
form2.ShowDialog();//Show Form2 as modal dialog.
}
Hope it would help you achieve what you need.Anything more,please let me know.
Proposally you start you form with form.ShowDialog(), which returns DialogResult. You should check whether it is DialogResult.Ok or whether form.DialogResult != DialogResult.None. In the form, if the user inserts the file you can set the form.DialogResult explicitely to DialogResult.Ok
Just you can handle the close event with your own logic
private void Form1_FormClosing_1(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show(text:"Are you sure you want to quit?",caption:string.Empty,buttons: MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
}

Closing form and capture closing event

everyone.
I've run into such a problem. In my app, I show second form from my main form through ShowDialog method. In this form I have some textBox(s) to connect to the DB and a Connect button. If user clicks X, the app exit. But if user click "connect" - I connect to DB and also close my second form. To catch closing event I use FormClosing method where the app asks whether I'm about to close the app and if yes it exit. The problem is that when I click the button, FormClosing event fires and asks me if I want to exit. How to avoid it? I try to use sender, but it doesn't work.
Here is my code:
private void Connect_Click(object sender, EventArgs e)
{
try
{
orcl.connect(userID.Text, Password.Text, comboTNS.Text);
if (orcl.ifHasRows("select dbclass from setupdbversion where dbclass='SECURITY' and rownum=1"))
{//my stuff
this.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
};
}
private void SecConnForm_FormClosing_1(object sender, FormClosingEventArgs e)
{
MessageBox.Show(sender.ToString());
if (e.CloseReason == CloseReason.UserClosing)
{
MessageBox.Show(sender.ToString());
if (string.Equals((sender as Form).Name, #"SecConnForm")) //it doesn't work as in any cases the sender is my form, not a button (when i click on button of course)
{
if (MessageBox.Show(this, "Really exit?", "Closing...",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
== DialogResult.Cancel)
e.Cancel = true;
else
Application.Exit();
}
else
{
//other stuff goes..
}
}
}
Form closing event will fire every time form is closed whether that is done by code or by user click.
What you need is something similar to this.
private boolean bFormCloseFlag = false;
private void Connect_Click(object sender, EventArgs e)
{
try
{
orcl.connect(userID.Text, Password.Text, comboTNS.Text);
if (orcl.ifHasRows("select dbclass from setupdbversion where dbclass='SECURITY' and rownum=1"))
{//my stuff
bFormCloseFlag = true;
this.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
};
}
private void SecConnForm_FormClosing_1(object sender, FormClosingEventArgs e)
{
if (bFormCloseFlag = false)
{
MessageBox.Show(sender.ToString());
if (e.CloseReason == CloseReason.UserClosing)
{
MessageBox.Show(sender.ToString());
if (string.Equals((sender as Form).Name, #"SecConnForm")) //it doesn't work as in any cases the sender is my form, not a button (when i click on button of course)
{
if (MessageBox.Show(this, "Really exit?", "Closing...",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
== DialogResult.Cancel)
e.Cancel = true;
else
Application.Exit();
}
else
{
//other stuff goes..
}
}
}
}
This flag will simply check whether form is closed by 'X' button click or it is closed by your code.
The this.Close() triggers the closing type of "UserClosing"
Possibly just hide the dialog instead of this.close()?

Closing event triggered on both UserClosing and this.close

I have a form on which there is a LogOutEvent and a form closing event.
Here is the code,
private void btnLogOut_Click(object sender, EventArgs e)
{
DialogResult yesNo = MessageBox.Show(this, "Are you sure you want to Log Off?", "Log Off", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (yesNo == DialogResult.Yes)
{
new LoginForm();
this.Close();
string tst2 = Logout(AgentId, AgentPwd, ExtensionId);
if (tst2 == "TCF000")
MessageBox.Show(" Logout Success");
else
MessageBox.Show("Logout Failed");
}
}
And a Form Closing Event
private void MainGUI_FormClosing(Object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult yesNo = MessageBox.Show(this, "Are you sure you want to Log Off?", "Log Off", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (yesNo == DialogResult.Yes)
{
Application.Exit();
}
else
{
e.Cancel = true;
}
}
}
My Problem is when i click on the LogOut button its calling the form closing event. Can anybody advice a better code for this?
When i click on close 'X' it should close the application and when i click on LogOut it should close the current window and go to the login form.
I'm sure that there is a better solution, but this does work:
private bool loggingOut;
private void Form1_DoubleClick(object sender, EventArgs e)
{
this.loggingOut = true;
this.Close();
// This is optional as we are closing the form anyway
this.loggingOut = false;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing && !loggingOut)
{
// Handle form closing here
}
}
This allows your form closing event handler to identify if another method is invoking the form close, and skip the normal handling if it is.
Alternatively you could just Hide the form instead, and re-use the same form instance the next time the user logs in.
well... yes! the form is closing; why wouldn't it fire the event?
If the CloseReason isn't helping, then just throw a bool field onto the form that you set to true when you click logout; and check that field in the closing event.

Categories

Resources