I have a windows forms method that gets called:
// fire up the form
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
form.ShowDialog();
Then inside of that form I have a routine that gets run:
private void btnOK_Click(object sender, EventArgs e)
{
renumberViewports();
}
now if during execution of renumberViewports() it encounters a certain condition I am asking it to initiate a sub form to get user input on how to proceed:
if (openAdditionalForm)
{
ViewportRenumberingForm2 subForm = new ViewportRenumberingForm2();
var result = subForm.ShowDialog();
if (result == DialogResult.OK)
{
// get all values preserved after close
bool selected = subForm.ReturnSelected;
bool unselected = subForm.ReturnUnselected;
if (selected)
{
//do something
}
if (unselected)
{
//do something
}
}
else if (result == DialogResult.Cancel)
{
this.Show();
}
}
Now, the question is: When user hits Cancel I want to return to my main form and basically start over. That means that user can re-enter any information and hit that btnOK_Click() and renumberViewports() will get executed again. It's basically that I want ability for user to just acknowledge that their current input will cause an error, show them that in a sub form, allow them to cancel to re-enter inputs.
Then i want to re-execute it and close the form if there are no errors.
Right now, i got everything up to the Cancel input working. When user hits Cancel I return to my main form, but hitting OK on it, doesnt re-execute the renumberViewports() command.
Any help will be appreciated.
If I understand what you are trying to do, in your renumberViewports() method, change your DialogResult.Cancel conditional block to this:
else if (result == DialogResult.Cancel)
{
// this will close this form and set the result to 'Cancel'
this.DialogResult = DialogResult.Cancel;
}
Then, in you main form, instead of simply:
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
form.ShowDialog();
... I would change that to a loop that keeps reopening the ViewportRenumberingForm form until the result is not Cancel:
DialogResult result = DialogResult.Cancel;
while (result == DialogResult.Cancel)
{
ViewportRenumberingForm form = new ViewportRenumberingForm(pickedRef, doc);
result = form.ShowDialog();
}
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 am unable to determine why the following code fails to save changes to database during FormClosing event:
private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
{
if (bAreChanges)
{
DialogResult dialogResult = MessageBox.Show("Do you wish to save the changes to the database?",
"Confirmation", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
using (var context = new SomeEntities()) {
var value = "abc";
context.sometable.Add(new sometable() {somefield = value} );
context.SaveChanges();
//the same exact code works when executed from a simple button click that is placed on this form.
}
this.Validate(); // even added this line as suggested in another Stackoverflow question
}
else if (dialogResult == DialogResult.No)
{
}
else
{
e.Cancel = true;
}
}
}
Perhaps some part of SaveChanges() is asynchronous and therefore the Form disposes before the database operation is executed?
Edit: This is a child form, not the main form - the application keeps running after this form is closed. If this is somehow relevant.
Putting this.Validate() before the database operations made it work. I would, however, like to know why is that relevant in this case.
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.
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 have this sample code to show an alert MessageBox,
if (cmprLanguage != 0 || cmprmaxCase != 0 )
{
DialogResult result = MessageBox.Show("Alert message", "Alert", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result == DialogResult.OK)
{
loginscreen obj = new loginscreen();
this.Close();
obj.Show();
}
else
{
settings obj = settings(); //this re-load this form i need to show this form without reload
obj.show();
}
}
else
{
loginscreen obj = new loginscreen();
this.Close();
obj.Show();
}
If user clicks cancel button I need to close the MessageBox,if they click ok I need to perform the process given inside OK block. Now what happen is if I click Cancel button the application redirect to home screen.
Update:
I had written a closed event for close icon in form screen.Previously when i click close icon it directly takes me to login screen because login screen is behind this form screen.Some times user may enter data and without save if he hit close icon i have raise a messagebox to alert the user.But now if i click cancel it again takes me to login screen and if i click ok it perform the task inside the condition.If i click Cancel i need to show the current screen with the action performed(without reload of page)
Is it possible to do this?
Your code is already working as expected. But for clearance you could put the result of the MessageBox.Show() in a variable instead. This makes it easier to maintain and process in further code. Like this:
DialogResult result = MessageBox.Show("Settings not saved", "Alert", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
And then handle it in code:
if(result == DialogResult.OK)
{
//Show new data
}
else if (result == DialogResult.Cancel)
{
//Show current data
}
Update:
Your code is not correct they way you've provided it to us: you cannote have two else statements after eachother.
Why don't you just leave the else part away. Only perform an action when the user clicks OK. When the user clicks OK, that means he'll leave the current form without saving the pending changes. When he chooses Cancel, it means that he wants to stay wherever he is at that moment:
DialogResult result = MessageBox.Show("Settings not saved", "Alert", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result == DialogResult.OK)
{
//User leaves without saving pending changes
loginscreen ob = new loginscreen();
this.Close();
ob.Show();
}
//No else: just stay wherever you are.
DialogResult result = MessageBox.Show("Settings not saved", "Alert", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result == DialogResult.OK)
{
loginscreen ob = new loginscreen();
this.Close();
ob.Show();
}
In my opinion this actually satisfies your needs. It is your original code, let me explain.
The MessageBox gets shown and asks the user if he/she wants to Cancel or agrees (OK) with the data being dropped because the form gets closed. Then, as your code was already designed, it creates a new loginscreen and allows the user to do other stuff.
This actually appears to be all you need. You want the user to stay on the current form is the Cancel-button is clicked, which is exactly what happens if you only use this particular piece of code. No else is needed because nothing else needs to happen.
If you do want other code to be executed in the else-statement, you could think about creating a new form and placing OK and Cancel buttons on that yourself (create your own "custom MessageBox"). This will allow you some more options if really needed. But looking at what you are trying to achieve, you are good with the current set up of only an if and no else-statements.