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;
}
}
Related
Here is my C# code:
private void StudentReg_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult dialog = MessageBox.Show("Do you really want to close this window?", "Exit", MessageBoxButtons.YesNo);
if (dialog == DialogResult.Yes)
{
Application.Exit();
}
else if (dialog == DialogResult.No)
{
e.Cancel = true;
}
}
Depending on how you setup your application like if this is your main form or you have multiple you may need to just remove the event to avoid duplicate calls to it.
Remove the event handler before calling application.exit and I think your issue will be solved.
This is psuedo-code.
private void StudentReg_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult dialog = MessageBox.Show("Do you really want to close this window?", "Exit", MessageBoxButtons.YesNo);
if(dialog == DialogResult.Yes)
{
StudentReg.FormClosing -= StudentReg_FormClosing;
Application.Exit();
}
else if(dialog == DialogResult.No)
{
e.Cancel = true;
}
}
I doubt if you really want Application.Exit();: you prompt (bold is mine)
Do you really want to close this window
It is the window (Form), not the entire Aplication you want to close. If it's your case, you can just do nothing and let the form (window) close itself:
private void StudentReg_FormClosing(object sender, FormClosingEventArgs e)
{
// Cancel closing (i.e. do NOT close the form) if and only if user's chosen "No".
// Do nothing (i.e. do not cancel) in other cases (let the form be closed)
// So we assign true (cancel) if "No" has been pressed, false otherwise
e.Cancel = MessageBox.Show(
"Do you really want to close this window?",
"Exit",
MessageBoxButtons.YesNo) == DialogResult.No;
}
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.
I am learning about Forms and somehow can't figure out what's the problem with this code that when I want to press either button with Dialog.Result.Yes or button with Dialog.Result.No in Form2 to keep the Form2 open it anyway closes after clicking on one of them.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_MouseClick(object sender, MouseEventArgs e)
{
Formular2 Form2 = new Formular2();
Form2.ShowDialog();
if (Form2.DialogResult == DialogResult.Yes)
{
this.DialogResult = DialogResult.None;
}
else if (Form2.DialogResult == DialogResult.No)
{
DialogResult = DialogResult.None;
}
}
}
Thanks for any advice
If you want to keep the Form2 open, you need to set the DialogResult property of Form2, not the DialogResult property of Form1.
You need to move this logic in the button on Form2 that close the Form2
So, suppose to have a button on Formular form class named buttonOK and its property DialogResult is set to DialogResult.OK.
Then in that class code you write the event handler for the button click event (not the MouseClick event)
private void buttonOK_Click(object sender, MouseEventArgs e)
{
// Perform some logic to validate the inputs and if something is wrong return false
if(SomeLogicToAcceptTheForm() == false)
{
// Inform the user of the error
MessageBox.Show("Your input is not valid");
// Stop the closing process of this Formular instance
this.DialogResult = DialogResult.None;
}
// If your logic accepts the input, then the code continue at this point
// This will cause the form to exit from the ShowDialog call
// and you can read the current form DialogResult value.
}
EDIT
To better understand this flow you should consider that, BEFORE calling the event handler for the button click event, the forms engine sets the Form's DialogResult property from the value present in the button's DialogResult property. So, if your validation turns out to be correct you don't need to do anything and the form closes returning DialogResult.OK (or whatever you have put in the Button's DialogResult property).
The act of setting a DialogResult will cause the Form to close returning that result to the Form that created the instance, that way it can check the result and take the appropriate action. In your case since you want to keep the second form open you either need to not assign the DialogResult.No to the button and do like Steve suggests or you can intercept the Form's FormClosing event, test for the DialogResult if DialogResult.No set to None and cancel the Closing of the Form.
Though I would suggest not using a DialogResult if you are wanting to keep the Form Open.
public Form2()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.No;
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Yes;
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.DialogResult == DialogResult.No)
{
DialogResult = DialogResult.None;
e.Cancel = true;
}
}
In the Form2 pick control for assigning respective dialog result.
Same DialogResult will be produced by the Form2 control if you click on it.
Example in Form2:
button1.DialogResult = DialogResult.Yes;
button2.DialogResult = DialogResult.No;
Now pressing any of these buttons should close the Form2.
If you want to restrict closing on button1 and button2. Following changes in the Click event are required:
private void button1_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.None;
}
Form1:
In result you could see what is result, by looking into Form2.DialogResult. You can do this as you get results from Form2 dialog:
Formular2 Form2 = new Formular2();
Form2.ShowDialog();
if (Form2.DialogResult == DialogResult.Yes)
{
//
}
else if (Form2.DialogResult == DialogResult.No)
{
//
}
On any windows form displayed as modal (using ShowDialog()), the act of setting DialogResult will cause to hide the modal form and return control to calling code. Read Remarks from this page of MSDN
If you wish to show your form again, you can do the following:
private void button1_MouseClick(object sender, MouseEventArgs e)
{
Formular2 Form2 = new Formular2();
Form2.ShowDialog();
if (Form2.DialogResult == DialogResult.Yes)
{
Form2.DialogResult = DialogResult.None;
}
else if (Form2.DialogResult == DialogResult.No)
{
Form2.DialogResult = DialogResult.None;
}
Form2.Show(); // or Form2.ShowDialog()
}
I am using C# here. I have a form where the user can select Yes or No, and if they choose No, a message box appears and asks them if they are sure. If they click No, I want to show the form again. Here's my code:
public void function()
{
MyForm form = new MyForm();
if (form.ShowDialog() == DialogResult.No)
{
if (MessageBox.Show("Are you sure?",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
runFinished.Dispose();
return;
}
else
{
//Show form again. How??
}
}
}
Thanks everybody for your help!
Arrange that the No button MyForm does the call to MessageBox. Only if the user is sure do you then go on to close the dialog. Your current approach of asking the question after the dialog has closed is incorrect.
You can effect the change by making sure that DialogResult is set in code rather than by the No button's DialogResult property. Then in the click handler for the button you run the message box. If the user confirms the action, then set the forms DialogResult to DialogResult.No.
Call two events depending on whether no or yes is selected (within MyForm). For example
void OnNoEvent(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
this.DialogResult = DialogResult.No;
this.Close();
}
}
void OnYesEvent(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Yes;
this.Close();
}
This is probably better than opening the dialog box many times.
Then the code to open the dialog is easy.
MyForm form = new MyForm();
if (form.ShowDialog() == DialogResult.No)
// perform actions here
There is the standart means: Form.FormClosing.
See example: example
Maybe I am missing something here, but why not use a while loop?
public void function()
{
MyForm form = new MyForm();
while(form.ShowDialog() == DialogResult.No)
{
if (MessageBox.Show("Are you sure?",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
runFinished.Dispose();
return;
}
}
}
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.