I want to reload the current form (not the main form) whenever both of the radio buttons are unchecked. I did this but it won't work.
StreamWriter sw;
using (sw = File.CreateText(path))
{
if (OnewayRadio.Checked == true)
{
sw.WriteLine("One Way Ticket");
}
else if (RoundRadio.Checked == true)
{
sw.WriteLine("Round Trip");
}
else
{
MessageBox.Show("You have not selected your type of trip!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
sw.Close();
File.Delete(path);
sw = File.CreateText(path);
}
sw.WriteLine("Name: " + name.Text);
sw.WriteLine("Number: " + number.Text);
}
A common practice is to open a form using ShowDialog
When your code in the form completes executing it will set a public DialogResult
The caller can then read the DialogResult and take any necessary action.
In your case, you can set the DialogResult to Retry for this specific instance. The opener can then run a loop and continue to show the form again while ShowDialog() == DialogResult.Retry
Form2 testDialog = new Form2();
// Show testDialog as a modal dialog and determine if DialogResult = OK.
while (testDialog.ShowDialog() == DialogResult. Retry)
{
testDialog.Dispose();
testDialog = null;
testDialog = new Form2();
}
The answer here assumes that the form to reopen is allowed to be modal. That is not always the case. I ran into the issue when making a form non-modal instead of modal.
Use .Hide() instead of .Close().
Place the Hide in the FormClosing() event like so,
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
e.Cancel = true;
}
After the form is "closed" in this way, a next call to Show() will have no issue.
In my case, some actions after closing the form had to be executed. If you normally open in Modal state, the ShowDialog() will return when the form is closed, like so
{
// ..
form1.ShowDialog();
OperationsAfterClose(form1);
// ..
}
A non-modal call form.Show() will return immediately. So any epilogue like my OperationsAfterClose() would be called immediately.
I used a delegate to move the action, as follows,
public delegate void OnFormHide(FrmMapFerryAnalysisSpec2 f);
public partial class Form1 : Form
{
public OnFormHide OnForm1Hide = null;
// ..
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (OnForm1Hide!=null) OnForm1Hide (this); // call the delegate
Hide();
e.Cancel = true;
}
// ..
}
In the calling form I can now pass OperationsAfterClose() as a delegate,
{
// ..
form1.Show();
form1.OnForm1Hide = OperationsAfterClose; // set the delegate
// ..
}
NOTES:
in order to use this safely, the form1 handle should exist and must not be created multiple times !
Also in most applications, the form may only open once. To do that, easiest is to introduce a IsOpenForm1 boolean in the calling form.
Related
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;
}
}
I'm searching for the proper way how to open and switch forms some uses Application.Run( new Form1());, some uses Form1.ShowDialog(); and Form.Show();. I really want to know how to properly pass a data from a form into another using constructors.
Additionally I want to know why when I use Form.Close(); to close to current form before to open next form .... both forms closes.
Here are my codes.
try
{
Form2 f2 = new Form2(connection, userLogin);
this.Hide();
f2.ShowDialog();
}
catch (NullReferenceException nre) {
MessageBox.Show("Sorry Login Another User account");
}
What I'm trying to do here is to pass the MySqlConnection in the variable connection and the valid user in the variable userLogin into the Form2. This method works but I'm not sure if this the right way to do it.
Here are the codes in Form2.
public partial class Form2 : Form
{
MySqlConnection connection;
User activeUser;
public Form2(MySqlConnection pConn, User loginUser)
{
InitializeComponent();
connection = pConn;
activeUser = loginUser;
this.Init();
this.CenterToScreen();
}
private void logoutB_Click(object sender, EventArgs e)
{
this.Hide();
new Form1().Visible = false;
new Form1().ShowDialog();
//Application.Run(new Form1());
}
}
Showing the Form2 doesn't also have a problem but when the logout button is pressed.
Form that is already visible cannot be displayed as a modal dialog box.
Set the form's visible property to false before calling showDialog.
It says Form already visible? So does it mean the form is still open even though I used this.Hide();? and when I use the code Application.Run(new Form1());
Starting a second message loop on a single thread is not a valid operation.
Use Form.ShowDialog instead.
In this section of code:
new Form1().Visible = false;
new Form1().ShowDialog();
You are simply creating two new forms; you are creating a form in the first line with Visibilityproperty set to false; and in the second line you are creating a new Form and calling ShowDialog on it. So two instances are not the same.
this.Hide();
Form1 a = new Form1();
a.Visible = false;
a.ShowDialog();
Since you use ShowDialog to show Form2 from Form1, then simply close the second form when the user clicks the logout button.
private void logoutB_Click(object sender, EventArgs e)
{
this.Close();
}
This will bring execution back to Form1 right after the ShowDialog call. So, make sure then you re-show the form after you invoke ShowDialog like this:
try
{
Form2 f2 = new Form2(connection, userLogin);
this.Hide(); //hide my self
f2.ShowDialog(); //show Form2.
//Execution will resume here after Form2 is closed
this.Show(); //re-show my self
}
catch (NullReferenceException nre)
{
MessageBox.Show("Sorry Login Another User account");
}
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 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();
}