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.
Related
I have a dialog that I want to prevent from closing when the OK button is clicked, but it returns, and that even if the AcceptButton property is set to none instead of my OK button. What is the best way to stop it from closing?
In fact you are changing the wrong property. You certainly do want AcceptButton to be the OK button. This property determines which is the default button in Windows terms. That is the button which is pressed when you hit ENTER on your keyboard. By changing AcceptButton you are simply breaking the keyboard interface to your dialog. You are not influencing in any way what happens when the button is pressed.
What you need to do is set the DialogResult property of your button to DialogResult.None since that's what determines whether or not a button press closes the form. Then, inside the button's click handler you need to decide how to respond to the button press. I expect that, if the validation of the dialog is successful, you should close the dialog by setting the form's DialogResult property. For example
private void OKbuttonClick(object sender, EventArgs e)
{
if (this.CanClose())
this.DialogResult = DialogResult.OK;
}
The best way to stop this behavior is changing the DialogResult property of your OK button to DialogResult.None in the property window at design time.
Also, If you have already some code in the click event of the OK button you could change the form DialogResult.
private void comOK_Click(object sender, EventArgs e)
{
// your code .....
// Usually this kind of processing is the consequence of some validation check that failed
// so probably you want something like this
if(MyValidationCheck() == false)
{
// show a message to the user and then stop the form closing with
this.DialogResult = DialogResult.None;
}
}
You need to remove the DialogResult of the button itself as well, in the properties window on the button set it to None.
http://msdn.microsoft.com/en-us/library/system.windows.forms.button.dialogresult.aspx
If the DialogResult for this property is set to anything other than
None, and if the parent form was displayed through the ShowDialog
method, clicking the button closes the parent form without your having
to hook up any events.
Obviously, now your button won't do anything so you will need to register a handler for the Click event.
The best practice is to actually set the Ok button to be disabled rather than not respond to user input.
The DialogResult property SHOULD be set to Ok or Yes depending on the form and the AcceptButton should also be linked to Ok.
I normally create a function on all dialogs and call it whenever the user interacts with the data.
void RefreshControls()
{
button.Enabled = this.ValidateInput();
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form2 fLogin = new Form2();
if (fLogin.ShowDialog() == DialogResult.OK)
{
Application.Run(new Form1());
}
else
{
Application.Exit();
}
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void btnKlik_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
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();
}
}
}
}
I have two forms.
The first form is the mainForm, this never goes anywhere.
On opening the second form (saveForm), it will display over the top.
When i close this form, I want a certain piece of code in the mainForm to run.
I assume this is the correct way to get this to happen?
The code on saveForm when I close and return to the mainForm:
private void btnSaveDetails_Click(object sender, EventArgs e)
{
Delivery d = new Delivery(txtNameBox.Text, txtAddressBox.Text, txtDayBox.Text, txtTimeBox.Text, txtMealBox.Text, txtInstructionsBox.Text, txtStatusBox.Text);
mainForm.myDeliveries.Add(d);
this.Close();
}
Any ideas?
You can use the DialogResult returned to effect some change in your application. For example, if you provided the user with a dialog asking whether or not they want to delete all files and they respond by clicking the Yes button on your dialog, you would then delete the files.
More information about how to use DialogResult and ShowDialog vcan be found here: DialogResult
UPDATE: If the code you posted is from your "child" form, then what you've done so far is probably fine, BUT, you still need to provide a DialogResult on that form to communicate to mainForm that something was done. For example, you could do the following before this.Close():
this.DialogResult = DialogResult.OK;
Then, in the code after the call to childForm.ShowDialog(), check the DialogResult. If it's equal to DialogResult.OK, then you can perform whatever task you need to that indicates the user clicked OK.
(And, on a side note, Dispose() is not called when you use ShowDialog(); you'll need to clean things up yourself, if necessary.)
You have to set the DialogResult property of you dialog form. Either explicitly in code or by assingning the dialog result to a button on your form.
private void btnSaveDetails_Click(object sender, EventArgs e)
{
Delivery d = new Delivery(
txtNameBox.Text, txtAddressBox.Text, txtDayBox.Text,
txtTimeBox.Text, txtMealBox.Text, txtInstructionsBox.Text,
txtStatusBox.Text
);
mainForm.myDeliveries.Add(d);
this.DialogResult = DialogResults.OK;
}
No need to call Close() setting this.DialogResult does that for you if you called the dialog using ShowDialog().
On calling the form you have to do the following:
var frm = new MyForm();
if (frm.ShowDialog() == DialogResults.OK) {
// do what you want to do on success.
}
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.
I use C#.
I have a Windows Form with an edit box and a Cancel button. The edit box has code in validating event. The code is executed every time the edit box loses focus. When I click on the Cancel button I just want to close the form. I don't want any validation for the edit box to be executed. How can this be accomplished?
Here is an important detail: if the validation fails, then
e.Cancel = true;
prevents from leaving the control.
But when a user clicks Cancel button, then the form should be closed no matter what. how can this be implemented?
If the validation occurs when the edit box loses focus, nothing about the the cancel button is going to stop that from happening.
However, if the failing validation is preventing the cancel button from doing its thing, set the CausesValidation property of the button to false.
Reference: Button.CausesValidation property
Obviously CausesValidation property of the button has to be set to false and then the validating event will never happen on its click. But this can fail if the parent control of the button has its CausesValidation Property set to true. Most of the time developers misses/forgets to change the CausesValidation property of the container control (like the panel control). Set that also to False. And that should do the trick.
I was having problems getting my form to close, since the validation of certain controls was stopping it. I had set the control.CausesValidation = false for the cancel button and all the parents of the cancel button. But still was having problems.
It seemed that if the user was in the middle of editing a field that was using validation and just decided to give up (leaving the field with an invalid input), the cancel button event was being fired but the window would not close down.
This was fixed by the following in the cancel button click event:
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the validation of any controls so the form can close.
AutoValidate = AutoValidate.Disable;
Close();
}
Set the CausesValidation property of the Cancel button to false.
Set the CausesValidation property to false.
None of these answers quite did the job, but the last answer from this thread does. Basically, you need to:
Insure that the Cancel button (if any) has .CausesValidation set to false
Override this virtual method.
protected override bool ProcessDialogKey(Keys keyData) {
if (keyData == Keys.Escape) {
this.AutoValidate = AutoValidate.Disable;
CancelButton.PerformClick();
this.AutoValidate = AutoValidate.Inherit;
return true;
}
return base.ProcessDialogKey(keyData);
}
I didn't really answer this, just pointing to the two guys who actually did.
Setting CausesValidation to false is the key, however this alone is not enough. If the buttons parent has CausesValidation set to true, the validating event will still get called. In one of my cases I had a cancel button on a panel on a form, so I had to set CausesValidation = false on the panel as well as the form. In the end I did this programatically as it was simpler than going through all the forms...
Control control = cancelButton;
while(control != null)
{
control.CausesValidation = false;
control = control.Parent;
}
In my case, in the form I set the property AutoValidate to EnableAllowFocusChange
By using Visual Studio wizard you can do it like that:
Judicious use of the Control.CausesValidation property will help you achieve what you want.
Just above the validation code on the edit box add:
if (btnCancel.focused)
{
return;
}
That should do it.
In complement of the answer of Daniel Schaffer: if the validation occurs when the edit box loses focus, you can forbid the button to activate to bypass local validation and exit anyway.
public class UnselectableButton : Button
{
public UnselectableButton()
{
this.SetStyle(ControlStyles.Selectable, false);
}
}
or if you use DevExpress:
this.simpleButtonCancel.AllowFocus = false;
Note that doing so will change the keyboard experience: the tab will focus anymore on the cancel button.
Maybe you want to use BackgroundWorker to give little bit delay, so you can decide whether validation should run or not. Here's the example of avoiding validation on form closing.
// The flag
private bool _isClosing = false;
// Action that avoids validation
protected override void OnClosing(CancelEventArgs e) {
_isClosing = true;
base.OnClosing(e);
}
// Validated event handler
private void txtControlToValidate_Validated(object sender, EventArgs e) {
_isClosing = false;
var worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
// Do validation on complete so you'll remain on same thread
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (!_isClosing)
DoValidationHere();
}
// Give a delay, I'm not sure this is necessary cause I tried to remove the Thread.Sleep and it was still working fine.
void worker_DoWork(object sender, DoWorkEventArgs e) {
Thread.Sleep(100);
}
This is an old question however I recently ran into this issue and solved it this way:
1st, we are loading a UserControl into a 'shell' Form that has a save and cancel button. The UserControl inherit an interface (like IEditView) that has functions for Save, Cancel, Validate and ToggleValidate.
In the shell form we used the mouse enter and mouse leave like so:
private void utbCancel_MouseEnter(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
private void utbCancel_MouseLeave(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
Then in ToggleValidate (Say a simple form with two controls...you can always just loop through a list if you want) we set the CausesValidation
public bool ToggleValidate()
{
uneCalcValue.CausesValidation = !uneCalcValue.CausesValidation;
txtDescription.CausesValidation = !txtDescription.CausesValidation;
return txtDescription.CausesValidation;
}
Hope this helps.
I found this thread today while investigating why my form would not close when a validation error occurred.
I tried the CausesValidation = false on the close button and on the form itself (X to close).
Nothing was working with this complex form.
While reading through the comments I spotted one that appears to work perfectly
on the form close event , not the close button (so it will fire when X is clicked also)
This did the trick.
AutoValidate = AutoValidate.Disable;
Create a bool:
bool doOnce;
Set it to false in your function and then:
if (doOnce == false)
{
e.cancel = true;
doOnce = true;
}
This means it will only run once and you should be able to cancel it. This worked for me anyways.
This work for me.
private void btnCancelar_MouseMove(object sender, MouseEventArgs e)
{
foreach (Control item in Form.ActiveForm.Controls)
{
item.CausesValidation = false;
}
}