Saving changes to database during FormClosing fails - c#

I am unable to determine why the following code fails to save changes to database during FormClosing event:
private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
{
if (bAreChanges)
{
DialogResult dialogResult = MessageBox.Show("Do you wish to save the changes to the database?",
"Confirmation", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
using (var context = new SomeEntities()) {
var value = "abc";
context.sometable.Add(new sometable() {somefield = value} );
context.SaveChanges();
//the same exact code works when executed from a simple button click that is placed on this form.
}
this.Validate(); // even added this line as suggested in another Stackoverflow question
}
else if (dialogResult == DialogResult.No)
{
}
else
{
e.Cancel = true;
}
}
}
Perhaps some part of SaveChanges() is asynchronous and therefore the Form disposes before the database operation is executed?
Edit: This is a child form, not the main form - the application keeps running after this form is closed. If this is somehow relevant.

Putting this.Validate() before the database operations made it work. I would, however, like to know why is that relevant in this case.

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;
}
}

C# Windows Form formclosing error

i am pretty newbie for coding. Here is i am having a problem:
private void pano_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult dialog = MessageBox.Show("Uygulamadan çıkış yapmak istediğinizden emin misiniz?", "Çıkış", MessageBoxButtons.YesNo);
if (dialog == DialogResult.Yes)
{
Application.Exit();
}
else if (dialog == DialogResult.No)
{
e.Cancel = true;
}
My purpose with this code block to ask user "are sure to quit" but unfortunetly when i close the application, i got notification window for 3 times? Is there any idea why thats happening or any solution?
Thanks a lot.
Nuri.
Firstly, as Steve pointed out, remove the 'Yes' part - if not explicitly canceled, the event will close that form as a result of clicking.
Now, for the problem of yours. Seems like your alert is called twice. I was able to solve that easily by making a static bool close_alert_shown, and when the first alert is shown, set it to true so that the next alert won't pop up.
Final code looks like that:
if (close_alert_shown) return;
close_alert_shown = true;
DialogResult dialog = MessageBox.Show("Uygulamadan çıkış yapmak istediğinizden emin misiniz?", "Çıkış", MessageBoxButtons.YesNo);
if (dialog == DialogResult.No)
{
e.Cancel = true;
close_alert_shown = false;
}
And on the top of the form (before the public Form1() contructor line):
static bool close_alert_shown = false;
What i suspect is when application is exiting, it is again calling form closing since we have subscribed for that event. I assume, simple fix would be unsubscribe from the event before calling exit.
this.FormClosing-=Form1_FormClosing;
Application.Exit();

windows form and subform routine

I have a windows forms method that gets called:
// fire up the form
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
form.ShowDialog();
Then inside of that form I have a routine that gets run:
private void btnOK_Click(object sender, EventArgs e)
{
renumberViewports();
}
now if during execution of renumberViewports() it encounters a certain condition I am asking it to initiate a sub form to get user input on how to proceed:
if (openAdditionalForm)
{
ViewportRenumberingForm2 subForm = new ViewportRenumberingForm2();
var result = subForm.ShowDialog();
if (result == DialogResult.OK)
{
// get all values preserved after close
bool selected = subForm.ReturnSelected;
bool unselected = subForm.ReturnUnselected;
if (selected)
{
//do something
}
if (unselected)
{
//do something
}
}
else if (result == DialogResult.Cancel)
{
this.Show();
}
}
Now, the question is: When user hits Cancel I want to return to my main form and basically start over. That means that user can re-enter any information and hit that btnOK_Click() and renumberViewports() will get executed again. It's basically that I want ability for user to just acknowledge that their current input will cause an error, show them that in a sub form, allow them to cancel to re-enter inputs.
Then i want to re-execute it and close the form if there are no errors.
Right now, i got everything up to the Cancel input working. When user hits Cancel I return to my main form, but hitting OK on it, doesnt re-execute the renumberViewports() command.
Any help will be appreciated.
If I understand what you are trying to do, in your renumberViewports() method, change your DialogResult.Cancel conditional block to this:
else if (result == DialogResult.Cancel)
{
// this will close this form and set the result to 'Cancel'
this.DialogResult = DialogResult.Cancel;
}
Then, in you main form, instead of simply:
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
form.ShowDialog();
... I would change that to a loop that keeps reopening the ViewportRenumberingForm form until the result is not Cancel:
DialogResult result = DialogResult.Cancel;
while (result == DialogResult.Cancel)
{
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
result = form.ShowDialog();
}

Button is closing WindowsForm automatically

I have a WinForms application that checks for pending changes whenever the user hits the cancel button. If there are pending changes, I prompt the user to see if they are sure they wish to cancel. If they do, I close the form. If not, I just return. However, the form is closing anyways. After some debugging, I realized it was because this particular button is set to the form's CancelButton, so clicking it caused the form to close. To verify, I removed the CancelButton property, but the behavior persisted.
How can I prevent this automatic closing? Here is my event handler code:
private void closeButton_Click(object sender, EventArgs e)
{
DialogResult dr = DialogResult.Yes;
if (changesMade)
{
dr = MessageBoxEx.Show(this, "Are you sure you wish to disregard the changes made?", "Changes Made", MessageBoxButtons.YesNo);
}
if (dr == DialogResult.Yes)
{
Close();
}
else
{
//TODO:
}
}
In the above code, the form should only close if there are no changes made, or if the user chose to disregard them. I made changes, and clicked 'No' to the DialogBox, but the form still closed. With and without the button set as the form's CancelButton.
Just set the property DialogResult of the form to the enum DialogResult.None
....
if (dr == DialogResult.Yes)
{
Close();
}
else
{
this.DialogResult = DialogResult.None;
}
or simply:
if (dr != DialogResult.Yes)
this.DialogResult = DialogResult.None;
The form closes automatically because the property DialogResult of the button is not set to DialogResult.None in the Forms Designer. In this scenario, the WinForms engine takes that value and assign it to the DialogResult property of the whole form causing it to automatically close. This is usually used in the calling code of the form to distinguish between a Confirm and a Cancel button
In the example below suppose that on the frmCustomers there are two buttons, one with the DialogResult property set to DialogResult.OK and another set to DialogResult.Cancel. Now if the user hits the OK button you know, in the calling code what to do with the inputs for your new customer
using(frmCustomers f = new frmCustomers())
{
if(f.ShowDialog() == DialogResult.OK)
{
// Execute code to save a customer
}
}
Following up on my comment, this is what I do for an internal tool I wrote recently:
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = !PromptUnsavedChanges();
}
private bool PromptUnsavedChanges()
{
if (HasFormChanged()) //checks if form is different from the DB
{
DialogResult dr = MessageBox.Show("You have unsaved changes. Would you like to save them?", "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dr == System.Windows.Forms.DialogResult.Yes)
tsmiSave_Click(null, null); // Saves the data
else if (dr == System.Windows.Forms.DialogResult.Cancel)
return false; // Cancel the closure of the form, but don't save either
}
return true; // Close the form
}
The logic could probably cleaned up from a readability point of view, now that I'm looking at it months later. But it certainly works.
With this you simply just call this.Close(); in your button click event. Then that event is what handles the prompting and decides if it should actually close or not.

Categories

Resources