I'm opening a modal dialog asking the user to fill certain fields.
if(dlgUserDetail.ShowDialog() == DialogResult.OK)
{
}
On click of OK, the control comes to the parent form where I'm validating the user input.
If the validation fails, I wanted to keep the dialog to be open with the old values. Since it is modal dialog, the form gets closed.
It seems to be a common problem as I see many discussion on net, but nowhere I was able to find a solution.
Please let me know how to solve this problem. Thanks.
Regards
ArunDhaJ
If it is your dialog you could add a CancelEventArgs event called Validate or InputOk (similar to FileOk in OpenFileDialog) and have your main form check the input in a method. Before calling DialogResult = DialogResult.OK in your dialog, you add a ´onValidate` call to check if the input is valid.
{
// dialog
{
if (onValidate()) {
DialogResult = DialogResult.OK;
}
}
private bool onValidate() {
CancelEventHandler handler = Validate;
if (handler == null) {
return true;
}
CancelEventArgs args = new CancelEventArgs();
handler(this, args);
return args.Cancel;
}
}
{
// form
{
dlgUserDetail.Validate += valid;
if(dlgUserDetail.ShowDialog() == DialogResult.OK) { }
}
private void valid(object sender, CancelEventArgs e) {
// check input and set
e.Cancel = true;
// if not valid
}
}
One solution is to put validate logic into dlgUserDetail form and invoke it on OnClosing event. If the validation failed then prevent the form from closing.
Related
I have a method that fires on a "Leave" event:
private void cmbBox1_Leave(object sender, EventArgs e)
{
bool error = true;
if (something == true)
{
//do stuff...
error = false;
}
if (error == true)
{
MessageBox.Show("Error!")
}
}
Problem is, that closing the form counts as "leaving focus" from the control, so when I close the form, the message box pops up. Is there a way I can catch the Form closing as an invalid parameter? I.e.
if (error == true && this.FormClosing == false)
{
MessageBox.Show("Error!")
}
Try using the Validating event instead of Leave.
Then in FormClosing, you can set this.AutoValidate = AutoValidate.Disable; and your validation won't be fired any more.
If you close the form via an OK or Cancel button, you may need to set CausesValidation = false on those buttons as well (maybe you want validation on OK, though).
RESOLVED: Turned out to be a visual studio problem. Closed visual studio, cleaned and rebuilt, and the value started showing. Thanks all for the help, sounds like I need to switch to VS2010.
This may not be the best, safest, or preferred way to pass values between forms, but this is the way I am attempting for the moment. So, please do help me to get this way working. After you provide an answer, you're more than welcome to add in some better ways of doing this.
The problem is, when the modal dialog box closes and I go back to the owner, the textbox value from the modal is an empty string rather than the actual value. I've read in several places this should not be the case, as the data should persist even after the modal box disposes. Here's my code.
public partial class PreferencesForm : Form
{
public PreferencesForm()
{
InitializeComponent();
}
private void okButton_Click(object sender, EventArgs e)
{
if (masterRadioButton.Checked == true)
{
if (password1TextBox.Text != password2TextBox.Text)
{
errorLabel.Text = "Passwords do not match, please re-enter both passwords and try again.";
this.Refresh();
}
else if (password1TextBox.Text == "" && password2TextBox.Text == "")
{
errorLabel.Text = "You must enter a password.";
}
else
{
okResultButton_Click(null, null);
}
}
else if (singleRadioButton.Checked == true)
{
okResultButton_Click(null, null);
}
}
private void cancelButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Dispose();
}
private void okResultButton_Click(object sender, EventArgs e)
{
// invisible button
this.DialogResult = DialogResult.OK;
this.Dispose();
}
And here is the code that calls the above form as a modal dialog box.
private void setPreferencesToolStripMenuItem_Click(object sender, EventArgs e)
{
PreferencesForm pf = new PreferencesForm();
DialogResult result = pf.ShowDialog();
if (result == DialogResult.OK)
{
if (pf.password1TextBox.Text != "")
{
masterPassword = pf.password1TextBox.Text;
}
else
{
masterPassword = null;
}
}
}
Thanks for any assistance. I'm getting pretty frustrated over here. >:(
Note: The ReadOnly property of the password1TextBox variable is correctly shown as true or false, depending on what I select in the modal form, but the text property will still not correctly display.
I'm guessing that Dispose will also dispose the controls it contains. After the controls have been disposed, the text is likely no longer valid either. Try Close rather than Dispose and then Dispose in the caller.
You should listen to the people answering your question. Dispose is supposed to clear out memory allocated, it doesn't matter if you can still get the ReadOnly property.
Don't call Dispose in the form, call dispose from the calling code, as in the example code from the ShowDialog method documentation (http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx#Y851). Note that Dispose is called just before the testDialog variable goes out of scope.
public void ShowMyDialogBox()
{
Form2 testDialog = new Form2();
// Show testDialog as a modal dialog and determine if DialogResult = OK.
if (testDialog.ShowDialog(this) == DialogResult.OK)
{
// Read the contents of testDialog's TextBox.
this.txtResult.Text = testDialog.TextBox1.Text;
}
else
{
this.txtResult.Text = "Cancelled";
}
testDialog.Dispose();
}
I propose just save the string of the control of your Dialog into string property, and retrieve value of that class property and not control's property value after Dialog is closed, and stop worrying about Dispose or not Dispose, or whatever else.
Hope this helps
I have a form. In that I got to show a dialog (on some circumstances) with Text and a Cancel button. I want to catch the event of that button in my form Or know if that cancel button was clicked.
How can this be done ? I believe this should be possible but can't make out how ?
From my mainForm I have BackgroundWorker. When the backgroundWorker is started I open a childForm (with a Label and a button) and when the background task is over, I close the childForm. What I want more is : when the button of childForm is clicked the ongoing task of backgroundWorker should be cancelled.
SOLUTION
In my childForm I have set CancelButton property as cancelBtn for the form. The othe code is :
private bool cancel;
public bool Cancel
{
get { return cancel; }
set { cancel = value; }
}
// Set the flag as true to indicate that Cancel button was actually pressed
private void cancelBtn_Click(object sender, EventArgs e)
{
Cancel = true;
}
In mainForm :
childDlg = new ChildDialog();
// wHILE cALLING
backgroundWorker1.RunWorkerAsync();
msg = "Connecting...";
childDlg .set(msg, "");
if (!childDlg .IsAccessible)
{
// This is caught even when the dialog is closed
if (childDlg .ShowDialog() == DialogResult.Cancel) {
if (childDlg.Cancel == true) { // Was really cancelBtn pressed
// NOW ONLY do my stuff
}
}
}
I had tried using #DeveloperX technique i.e. EventHandler in parent class, but the parent class method was nver being called. Tried a lot but couldn't success. Then tried of #RobinJ's technique and it worked. I just had to add flag to identify was really cancel button pressed or jjst windw was closed normally.
Thanks to all of you for tryig to help me out. I really appreciate your help.
Thanks
Set DialogResult property to either DialogResult.Ok or DialogResult.Cancel
Then in the parent form:
Form form = new Form();
DialogResult results = form.DialogResult;
if(results == DialogResult.Ok)
{
... make magic
}
else
{
...
}
Put this in the form that should catch the event:
frmDialog.ShowDialog();
And this in the btnCancel_Click event of the dialog:
return DialogResult.Cancel();
Sorry if I'm confusing VB and C# here, but it's pretty much the same.
Simply you can create an event for the form that shows the dialog
and handle this event in parent form
in case the user clicks on ok fire event with specefic parameter and for cancel another parameter (such dialogresult.cancel)
an pseudo implementation can be like this
public class FormChild : System.Windows.Forms.Form
{
public event EventHandler DialogCanceled;
public event EventHandler DialogConfirmed;
public void ShowDialog()
{
using (var dialogForm = new FormDialog())
{
if (dialogForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
if (DialogConfirmed != null)
DialogConfirmed(this,new EventArgs());
}
else
{
if (DialogCanceled != null)
DialogCanceled(this,new EventArgs());
}
}
}
}
public class ParentForm : System.Windows.Forms.Form
{
public void callChild()
{
using (var f = new FormChild())
{
f.DialogCanceled += new EventHandler(f_DialogCanceled);
f.DialogConfirmed += new EventHandler(f_DialogConfirmed);
f.ShowDialog();
}
}
void f_DialogConfirmed(object sender, EventArgs e)
{
throw new NotImplementedException();
}
void f_DialogCanceled(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
You should be using the ShowDialog method on the form you need to show as a dialog and then use the DialogResult property to communicate to the parent form the result of the dialog operation.
This way you handle the button click on the form that owns the button but set the DialogResult to DialogResult.Cancel to specify that the user pressed the cancel button.
A dialog is usually a blocking event, where eventhandling by the parent form would make no sense at all.
If it isn't a modal dialog, you can always create one or several public events in the popup form, that are triggered when the buttons are clicked. These events can then be caught by the parent form.
Don't expose your buttons to the parent form, it would be terrible oo-programming.
Use the following:
Form form = new Form();
switch (form.ShowDialog())
{
case DialogResult.Ok:
{
....
Break;
}
case DialogResult.Cancel:
{
....
Break;
}
}
Set the Form.AcceptButton and Form.CancelButton properties to the appropriate buttons.
Refer to the following:
Form.ShowDialog Method
DialogResult Enumeration
Form.AcceptButton Property
Form.CancelButton Property
after searching google and stackoverflow I'm unable to find an answer that helped me in my situation. I've got an application with a start menu(form). when the user presses the X(close) of a (any) form I reload the start menu. Now when that(menu) form gets closed I want to check and notify the user wheter any now hidden forms are in editing mode (with or without unsaved changes) if user presses cancel I want to show that form and stop the application from closing. Now my problem is how do i stop the application from stopping in the code of the other forms. I have an override of the dispose method of the subforms that calls this.close so the ok/cancel messagebox shows but after the MB the start menu closes anyway stopping the program. Should I look for a different method of handling these things or is there a method or eventhandler to modify so this /\ can work?
EDIT:
ok here's parts of the code in order of being called. Where does i go wrong?
private void Menu_FormClosing(object sender, FormClosingEventArgs e)
{
Global.Forms.Remove(this);
if (!Global.Clean_Forms())
{
e.Cancel = true;
Global.Forms.Add(this);
}
}
public static void Clean_Forms()
{
foreach (Form f in Forms)
{
if (f is Menu)
{
//do nothing
}
else
{
if (!f.IsDisposed)
{
f.Close();
}
}
}
if (Forms.Count != 0)
{
isClean = false;
/* String a = "";
foreach (Form f in Forms)
{
a += f.ToString() + ": ";
}
MessageBox.Show(a);*/
}
else
{
isClean = true;
}
}
Yet this doesnt work, application just closes down.
the closing event handler of random form
private void persoon_form_FormClosing(object sender, FormClosingEventArgs e)
{
if (editing)
{
DialogResult dr;
dr = MessageBox.Show("uw wijzigingen gaan verloren. Doorgaan?", "sluiten", MessageBoxButtons.OKCancel);
if (dr == DialogResult.Cancel)
{
e.Cancel = true;
}
else if (dr == DialogResult.OK)
{
Global.size = this.Size;
Global.position = this.Location;
Global.Forms.Remove(this);
Form f = Global.menu();
f.Show();
this.Dispose();
}
}//somethingelse}
EDIT: #cody gray changed onclose and clean_form still no effect, (shouldn't the messagebox in the Closing event of the subform be shown anyway? cause it doesnt)
You should not be doing this in the Dispose method. Instead, try handling the FormClosing event.
This event occurs before the form is closed, so you can check whatever state you need to, and cancel the close if necessary by setting e.Cancel to True.
For example:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
// Check to see if the user is allowed to close this form
if (!allowClose)
{
// Prevent this form from being closed
MessageBox.Show("This form cannot be closed yet!");
e.Cancel = true;
}
}
I think i figured it out! I changed two things. 1 I made sure that I didn't call this.dispose anywhere as that will result in disposing (not closing) any child forms hence no onclosing event is called. 2. the foreach loop when checking if main menu can close generated collection was modified errors. so with this I made sure it closes in the right order thnx Cody Gray for pointing me in the right direction:
Stack<Form> stack = new Stack<Form>();
foreach (Form f in Forms)
{
if (f is Menu)
{
//do nothing
}
else
{
if (!f.IsDisposed)
{
stack.Push(f);
}
}
}
for (int i = 0; i < stack.Count; i++)
{
Form temp = stack.Pop();
temp.Close();
}
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.