Im playing about with some very simple windows forms. I have an event handler for a form close event that asks the user whether they want to save what they've typed:
private void closeNpForm(object sender, FormClosingEventArgs e)
{
if (!saveFlag)
{
if (MessageBox.Show("Do you want to save the text entered?", "Save Changes?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
e.Cancel = true;
saveFlag = true;
writeToFile(this.allText.Text);
}
}
}
if the user clicks yes (indicating they do want to save their text) i call the writeToFile method, and also set a flag so as not to ask them to save again:
private void writeToFile(string text)
{
writer = new StreamWriter("inputdata.txt");
writer.Write(text);
writer.Close();
this.Close();
}
As far as i can see, the writeToFile method should close the form when its finished. But this isnt happening, when i run the writeToFile method, the form just stays open. Can anyone tell me what im doing wrong?
as i understand it, calling this.Close() should trigger a form closing event, calling my event handler, due to the flag now being true, the form should just close without a problem.
note, my parent class extends the Form class, so im just using this to refer to my form instance.
e.Cancel = true -- whoops. The event is told cancel (read: not close the window).
I suspect that because close() is being called from within the close event and there is some internal clobbering going on (either suppressed or the Cancel is propagated over, etc). Just clean up the code (saving to the file has nothing to do with closing the window although the file might be saved and the window closed from within a button event.)
Happy coding.
writing to file and closing the form are two different kinds of operations. you should not have this.Close() in your writeToFile method.
As pst says, by setting e.cancel to true, you are basically telling the CloseForm event to be cancelled, therefore it's not closing once it exits from the closeNpForm event handler.
After exiting closeNpForm, the form checks for the Cancel property of the event and will not actually proceed with closing itself.
Why are you cancelling the close event and then calling writeToFile that closes the form?
In addition to what #pst said, why are you setting Cancel = true if you don't want to cancel the closing of the form?
If you remove e.Cancel = true; and this.Close(); it should do what you want.
This works for me:
public class Form1 : Form
{
bool saveFlag;
private void Form1_Load(object sender, EventArgs ev)
{ FormClosing += closeNpForm;
}
private void closeNpForm(object sender, FormClosingEventArgs e)
{
if (!saveFlag)
{
if (MessageBox.Show("Do you want to save the text entered?", "Save Changes?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
e.Cancel = true;
saveFlag = true;
this.Close();
}
}
}
}
Related
I am creating a small project using winforms + c#, I have an issue in that I am using a second form in my project as a dialogue box. When the user attempts to close this I'd like to provide them with a confirmation screen to prevent any data loss in closing the form. This dialogue box form will also feature a 'home' button, closing the dialogue box form leaving them with the main window again. The problem arises when the windows X button is pressed at the top of the screen requiring me to set up an 'on form close' event to manage. This however creates an infinite loop with my current code shown below. Is there any way to avoid this?
private void frmCreateRoute_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult Safe_to_exit_check = MessageBox.Show("Are you sure you would like to go to the home screen? \n(Any entered data will be lost.)", "", MessageBoxButtons.YesNo);
if (Safe_to_exit_check == DialogResult.Yes)
{
this.Close();
}
}
and a simple:
private void Home_button_Click(object sender, EventArgs e)
{
this.Close();
}
for the home button.
Thanks
In your FormClosing, set:
e.Cancel = true;
to prevent closing the form. Don't use this.Close() there.
You need to set e.Cancel=true if the user select any thing different than DialogResult.Yes, otherwise let the form close:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var result = MessageBox.Show("Are you sure you want to close the form?",
"Close", MessageBoxButtons.YesNoCancel);
if (result != System.Windows.Forms.DialogResult.Yes)
e.Cancel = true;
}
I'm developing a C# application and when the user clicks on the X, the application gets minimized inside a trayicon. Like so:
private void frmChat_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
The application is really simple (only one form). The problem is that I can't manage to properly close the application. When the user rights clicks on the tray icon and he chooses "exit" he should be able to close the application. The problem is that even if the tray icon gets unloaded and the form is closed, the application still shows in the Task Manager as an active application. I'm closing the application like this:
private void chiudiToolStripMenuItem_Click(object sender, EventArgs e)
{
trayIcon.Dispose();
this.Close();
Application.Exit();
}
What am I missing here?
I did something similar a while back.
You need to know what is causing the form to close. So when you click on the X, there is a specific reason passed to the FormClosing event. Like so:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
// don't close just yet if we click on x
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.Hide();
}
}
Also, I have other code from the context menu Exit click:
private void tsmiExit_Click(object sender, EventArgs e)
{
// close the application forefully
TerminateApplication();
}
/// <summary>
/// Closes the Application.
/// </summary>
private void TerminateApplication()
{
// need to forcefully dispose of notification icon
this.notifyIcon1.Dispose();
// and exit the application
Application.Exit();
}
Edit:
Note: When you click on the X button, the close reason will be a CloseReason.UserClosing. When Application.Exit is called, the FormClosing is called again with a CloseReason.ApplicationExitCall.
End Edit:
Hope this helps
Andez
The e.Cancel = true line in frmChat_FormClosing is blocking the app from shutting down.
You can solve this easily enough by adding a boolean field to your form class, named TerminatingApp. Set this to true before calling this.Close(). Inside frmChat_FormClosing check for the value of TerminatingApp and only set e.Cancel = true if TerminatingApp is false.
Something like this:
private void frmChat_FormClosing(object sender, FormClosingEventArgs e)
{
if (!TerminatingApp)
{
e.Cancel = true;
Hide();
}
}
private void chiudiToolStripMenuItem_Click(object sender, EventArgs e)
{
TerminatingApp = true;
trayIcon.Dispose();
this.Close();
Application.Exit();
}
Ciao, how does it work if you replace Application.Exit with Application.ExitThread ?
I am actually afraid that with your code, when you call this.Close you are getting into the previous method above with the cancelling...
This is where the documentation on Application.Exit() comes in handy (my emphasis in bold):
The Exit method stops all running
message loops on all threads and
closes all windows of the application.
This method does not necessarily force the application to exit. The
Exit method is typically called from
within a message loop, and forces Run
to return. To exit a message loop for
the current thread only, call
ExitThread.
You could call Environment.Exit(0) where the parameter is the exit code.
When you are calling "this.Close" its going to call "frmChat_FormClosing" and in that you are setting "e.Cancel = true" which is creating the problem, use some variable to identify from where close event is being called and set e.Cancel accordingly.
I have tried Environment.Exit(0). It works in this case, and it worked fine for me.
Everyone else is over doing it.
Just do Close();
I have an event handler subscribed to the FormClosing event. This event handler provides dialog for the user when they exit my application; like so:
private void frmUavController_FormClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
DialogResult dlgResult = MessageBox.Show("Are you sure you want to exit?", "Exit?",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dlgResult == DialogResult.Yes)
{
UtilSTKScenario.PauseScenarioAnimation(UtilSTKScenario._stkObjectRoot);
}
else if (dlgResult == DialogResult.No)
{
e.Cancel = true;
}
}
Because the application runs in a side-by-side fashion; injecting COM commands into another application - I want my application to exit if the application receiving COM commands is not launched (or closed during execution). This is achieved like so:
static UtilSTKScenario()
{
// give time for active form to show
Thread.Sleep(100);
_stkProgramId = ConfigurationManager.AppSettings.Get("stkProgramId");
if (CheckIfStkIsLaunched())
{
InitAllFields();
}
else
{
HideController dHideController = new HideController(((frmUavController)Form.ActiveForm).HideControllerUi);
((frmUavController)Form.ActiveForm).Invoke(dHideController);
Application.Exit();
}
}
Calling 'Application.Exit()' causes the FormClosing event to fire. This I do not want - rather, I want the application to just exit.
Any ideas ?
WulfgarPro
You might be able to look at the event args of the FormClosing event. FormClosingEventArgs has a CloseReason property that may give an indicator if the form was closed by a user directly as opposed to some other mechanism.
Though I'm not clear how Application.Exit() calls will appear... If it is also showing as CloseReason.UserClosing then you may need to add an overload to your form [e.g. SystemClose()] to close your form and use an instance variable to tell it not to prompt within your handler.
Your FormClosing event gets a FormClosingEventArgs parameter, which has a CloseReason property. If that's CloseReason.ApplicationExitCall, then the form is closing because of a call to Application.Exit. You can just skip your "close?" prompt in that case.
private void frmUavController_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.ApplicationExitCall)
return;
// ...
The typical way to handle this sort of thing (bypass normal "do you want to close?" checks) is to use a Boolean variable. Name it something like _forceExit, set it to true if the external event forces you to close, and if it's true, skip the dialog box in your Closing event.
Can you look at the sender object? My guess is that the sender object is different depending on you actually close the form or call the Application.Exit() method.
I have a dialog that I show with <class>.ShowDialog(). It has an OK button and a Cancel button; the OK button also has an event handler.
I want to do some input validation in the event handler and, if it fails, notify the user with a message box and prevent the dialog from closing. I don't know how to do the last part (preventing the close).
You can cancel closing by setting the Form's DialogResult to DialogResult.None.
An example where button1 is the AcceptButton:
private void button1_Click(object sender, EventArgs e) {
if (!validate())
this.DialogResult = DialogResult.None;
}
When the user clicks button1 and the validate method returns false, the form will not be closed.
Given that you've specified you want a pop error dialog, one way of doing this is to move your validation into a OnClosing event handler. In this example the form close is a aborted if the user answers yes to the question in the dialog.
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Determine if text has changed in the textbox by comparing to original text.
if (textBox1.Text != strMyOriginalText)
{
// Display a MsgBox asking the user to save changes or abort.
if(MessageBox.Show("Do you want to save changes to your text?", "My Application",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
// Cancel the Closing event from closing the form.
e.Cancel = true;
// Call method to save file...
}
}
}
By setting e.Cancel = true you will prevent the form from closing.
However, it would be a better design/user experience to display the validation errors inline (via highlighting the offending fields in some way, displaying tooltips, etc.) and prevent the user from selecting the OK button in the first place.
Don't use the FormClosing event for this, you'll want to allow the user to dismiss the dialog with either Cancel or clicking the X. Simply implement the OK button's Click event handler and don't close until you are happy:
private void btnOk_Click(object sender, EventArgs e) {
if (ValidateControls())
this.DialogResult = DialogResult.OK;
}
Where "ValidateControls" is your validation logic. Return false if there's something wrong.
You can catch FormClosing an there force the form to remain opened.
use the Cancel property of the event argument object for that.
e.Cancel = true;
and it should stop your form from closing.
This doesn't directly answer your question (other already have), but from a usability point of view, I would prefer the offending button be disabled while the input is not valid.
Use this code:
private void btnOk_Click(object sender, EventArgs e) {
if (ValidateControls())
this.DialogResult = DialogResult.OK;
}
The problem of it is that the user has to clic two times the buttons for closing the forms;
Just add one line in the event function
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
this->DialogResult = System::Windows::Forms::DialogResult::None;
}
I wish I had time to find a better example, but you would be much better off using the existing windows forms validation techniques to do this.
http://msdn.microsoft.com/en-us/library/ms229603.aspx
void SaveInfo()
{
blnCanCloseForm = false;
Vosol[] vs = getAdd2DBVosol();
if (DGError.RowCount > 0)
return;
Thread myThread = new Thread(() =>
{
this.Invoke((MethodInvoker)delegate {
picLoad.Visible = true;
lblProcces.Text = "Saving ...";
});
int intError = setAdd2DBVsosol(vs);
Action action = (() =>
{
if (intError > 0)
{
objVosolError = objVosolError.Where(c => c != null).ToArray();
DGError.DataSource = objVosolError;// dtErrorDup.DefaultView;
DGError.Refresh();
DGError.Show();
lblMSG.Text = "Check Errors...";
}
else
{
MessageBox.Show("Saved All Records...");
blnCanCloseForm = true;
this.DialogResult = DialogResult.OK;
this.Close();
}
});
this.Invoke((MethodInvoker)delegate {
picLoad.Visible = false;
lblProcces.Text = "";
});
this.BeginInvoke(action);
});
myThread.Start();
}
void frmExcellImportInfo_FormClosing(object s, FormClosingEventArgs e)
{
if (!blnCanCloseForm)
e.Cancel = true;
}
You can probably check the form before the users hits the OK button. If that's not an option, then open a message box saying something is wrong and re-open the form with the previous state.
Excuse me if this is a silly question but i'm a beginer here.
I have a simply custom dialog with two buttons: Accept and Cancel. The Accept button is the acceptButton of the form.
I want to do some validations on the Accept_Click event and decide if i can close the dialog or not, but everytime it leaves this method, the dialog automatically closes itself and returns Ok.
What can I do to stop the dialog from closing itself? or i have to do things in some other way?
thanks
I would have a form level variable (call it _vetoClosing) In the accept button's Click event, I would run validation and set the variable based on that:
private void acceptButton_Click(object sender, EventArgs e)
{
// Am I valid
_vetoClosing = !isValid();
}
Then in the FormClosing event, I would cancel close if _vetoClosing is true
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
// Am I allowed to close
if (_vetoClosing)
{
_vetoClosing = false;
e.Cancel = true;
}
}
Turning Accept button off is suboptimal because you loose the Enter to Press functionality.
A cleaner solution would be to set DialogResult to None:
private void acceptButton_Click(object sender, EventArgs e)
{
if (!isValid()) {
this.DialogResult = System.Windows.Forms.DialogResult.None;
}
}
I would validate as the controls change, and only enable the Accept button if the whole form is valid.
This would allow you to keep your button as the default button (AcceptButton), but prevent this from occurring.
Is the AcceptButton or CancelButton on the form set to that button? If so, try unsetting it and manually setting DialogResult in your handler when you want to close the dialog.