In an answer to a recent question I had (Here), Hans Passant stated that I should set the DialogResult to close my forms instead of form.Close() although I cannot seem to find out why?
If I've read correctly, the MSDN documentation states that doing this will just hide the form instead of correctly disposing it which I believed .Close() to do?
Extract from documentation.
The Close method is not automatically called when the user clicks the Close button of a dialog box or sets the value of the DialogResult property. Instead, the form is hidden and can be shown again without creating a new instance of the dialog box. Because of this behavior, you must call the Dispose method of the form when the form is no longer needed by your application.
On the other hand, Microsoft has created a support page that says how to use DialogResult property and in the "Verify It Works" section of this it states that clicking so will Close the form.
So my question is two fold, should I continue to use Close or DialogResult instead; and does dialog result close or hide a form. From the code I made below (a simple form with two buttons), it would seem that it is indeed hidden only as a breakpoint on this.Close() is hit..(with this.Close() commented, the form still disappears, just not sure whether hidden or not)
public Form1()
{
InitializeComponent();
button1.Click += (s, e) =>
{
//I edited my question to include using
using(Form1 form = new Form1())
{
form.ShowDialog();
}
};
button2.Click += (s, e) =>
{
this.DialogResult = DialogResult.OK;
this.Close();
};
}
When you open a modal dialog with ShowDialog, the calling code is blocked until the form called closes or hides. If you want to read some public properties of the called form and want to do things (for example save data to a database or to a file) based on the click on the OK or Cancel button, then you need to know if the user wants to do the action or not. The DialogResult returned by the ShowDialog() method allows you to take the appropriate actions...
So for example
using (Form1 form = new Form1())
{
DialogResult dr = form.ShowDialog();
if(dr == DialogResult.OK)
{
string custName = form.CustomerName;
SaveToFile(custName);
}
}
An important thing to add to this answer is the fact that the DialogResult property exists both on the Form class and in the Button class. Setting the button's DialogResult property (both via code or designer) to a value different from DialogResult.None is the key to activate an important behavior for forms. If you click a button with that property set then the Forms Engine transfers the value of the Buttons property to the Forms one and triggers the automatic closure of the form reactivating the caller code. If you have an event handler on the button click then you can run code to validate the form's inputs and force the form to stay open overriding the form's DialogResult property setting it back to DialogResult.None
For example, in the modally showed form you can have:
// Event handler for the OK button set with DialogResult.OK
public void cmdOK_Click(object sender, EventArgs e)
{
// Your code that checks the form data and
// eventually display an error message.
bool isFormDataValid = ValidateFormData();
// If data is not valid force the form to stay open
if(!isFormDataValid)
this.DialogResult = DialogResult.None;
}
Whether you call Close or set the DialogResult property is not really the issue. You just need to make sure to call Dispose. I prefer doing this with a using block:
using (Form1 form = new Form1())
{
form.ShowDialog();
}
I originally thought that you could call ShowDialog on a Form that has already had its Close method called. This is not the case. If you show the form modally with ShowDialog, it doesn't seem to matter whether it is closed as a result of the Close method, or setting the DialogResult property. It would seem that setting the DialogResult is just a short-cut for closing the Form.
But whether you call Close or set the DialogResult property, the key is to make sure that you call Dispose() or put your form in a using block.
Related
I have a form that I open using ParentForm.ShowDialog().
Inside this form I call:
using (var form = new ChildForm())
{
var result = form.ShowDialog();
if (result == DialogResult.OK)
{
this.Cancelled = false;
}
}
I'm getting odd behavior when the child dialog is closed, the parent (calling) form also closes.
Why is this happening and how do I stop it?
I have a current solution that prevents the closing of the parent form by using the ParentForm_FormClosing event and a Boolean, but it feels like an over complicated solution
A form opened modally is closed when you set the property DialogResult to anything but DialogResult.None. The common practice to close a modal form is to set the DialogResult property of one or more buttons to some value of the same named enum. In that way, when the form engine sees a call to a click event handler checks the value of the DialogResult of the clicked button and, if nothing change that value, it closes the form when the click event handler ends returning that enum value to the caller.
So, you probably have copy/paste that button leaving the original DialogResult property unchanged and clicking that button will trigger the closure of the hosting form.
Of course before closing the hosting form, the engine will call the button click event in which you open a modal dialog and this suspends everything until you close the child form. At that point the code exits the click event and the form engine continue closing your parent form returning to the caller the value of the DialogResult property of the button.
If you don't want to automtically close the hosting form then you can set the form's DialogResult in code with
this.DialogResult = DialogResult.None;
or change the value of the button's DialogResult property
My intention is to make a pop up window (using another form) and show it when the delete file event is triggered. On this pop up form user should enter a correct password and then click OK button, this pop up disappears and the deletion operation proceeds. What I did is setting a string variable "Result" in the pop up form(form 2). When clicking the OK button, if the password entered is correct the "Result" is set for example "true". In my main form I made like:
if(form2.Result=="true"){ // deletion operation}
However this method doesn't work. When I entered the correct password and click OK in form2, nothing happens in my main form. Anybody got any idea how could I in main form detect the button click event in form2? Something like "if(form2.button.click==true)".
Thank you
You are not supposed to detect a button click on the second form, you should restructure your flow.
There are two common ways to do this. The easiest for you to implement would be instead of calling form2.Show() which you are probably doing right now, you should call form2.ShowDialog() which will halt the execution of the method in form1 until form2 is closed
So in form1 you'd have something like
private void DeleteSomething() {
if (form2.ShowDialog() == DialogResult.Ok) {
if (form2.result == true)
doDelete();
}
}
Note that checking for the DialogResult is a common practice, and unless you assign the property on Form2 specifying which button will act as the "Ok" button, you need to manually set the dialog result inside form2 like Sayse mentioned in his reply with
this.DialogResult = DialogResult.OK;
In your case, using the dialog result is not strictly necessary, but it's a common practice to implement support for different dialog results (ok, cancel, etc)
The whole other method is to not treat form2 as a dialog, but have form1 pass a reference to itslef to form2
then in form2 you can call a method on form1 to "authorize" the delete
so form1 would have one private method "confirmDelete" which would just show form2
and another public method "doDelete" which would be called by form2 when needed.
Unrelated note on your code:
If you are going to use a variable to indicate weather the authentication was succsefull, don't use a string with the value of "true", use a boolean.
If you wanted to return 3 or more states (eg, Result could be "Ok" "User Canceled" "Incorrect password" "Inssuficcient privileges", etc) then use an Enumeration.
ShowDialog() method returns a DialogResult which you can set to indicate how the form exited
using(var form2 = MyFormName())
{
if(form2.ShowDialog() == DialogResult.OK)
//success -- You can access form2 properties also.
}
Inside your button_ok event on the form, set the DialogResult to OK
this.DialogResult = DialogResult.OK;
In my main form I am opening a new form (lets call it the parent form) using ShowDialog(). In the parent form I have a button which loads an OpenFileDialog, when I load the image and click Open button, OpenFileDialog closes but it also closes the parent window and I dont want this to happen.
Main form code:
// ADD GRAPHICS BUTTON
private void bAddGraphics_Click(object sender, EventArgs e)
{
NewGraphics newGraphics = new NewGraphics();
newGraphics.ShowDialog();
if (newGraphics.DialogResult == DialogResult.OK)
{
Core.Graphics tempGraphicsObject = new Core.Graphics();
tempGraphicsObject.name = newGraphics.name;
tempGraphicsObject.background = newGraphics.bgImage;
core.NewGraphics(tempGraphicsObject);
generateSingleGraphicsControl(core.project.graphics[core.project.graphics.Count-1].id, core.project.graphics[core.project.graphics.Count-1].name);
}
newGraphics.Dispose();
}
Parent form(dialog)
OpenFileDialog openFileDialog = new OpenFileDialog();
DialogResult result = openFileDialog.ShowDialog();
if (result == DialogResult.OK)
{
tbBackground.Text = openFileDialog.FileName;
bgImage = Image.FromFile(tbBackground.Text);
}
openFileDialog.Dispose();
Is it because I use DialogResult twice or maybe because I call ShowDialog() in a dialog window ? If I won't use ShowDialog() on a parent but just Show() it works fine but then I can't use DialogResult property. Is there a way around it or you just can't use ShowDialog() twice ?
If the "parent" Form is closing too, then you're either calling Close() or setting the DialogResult property on the Form (which will also close it).
From MSDN, regarding the DialogResult property:
If the form is displayed as a dialog box, setting this property with a value from the DialogResult enumeration sets the value of the dialog box result for the form, hides the modal dialog box, and returns control to the calling form.
I don't see you doing either one of those in the code you posted, but check for a line like one of these in your "parent" Form:
DialogResult = DialogResult.OK;
this.DialogResult = DialogResult.Cancel;
Close();
this.Close();
I know I'm digging up an old post, but I just ran into this and found another situation that can cause this. It's common to copy/paste form controls and reuse them for other purposes. Make sure that if you copied your form's OK or Cancel button for the Browse File button that you remove the DialogResult value. I had done this and forgot to remove the DialogResult.OK from my folder browser button. Apparently, the DialogResult assignment will happen after the click event making it appear that the dialog closed its parent.
In a multiple projects solution I had a startup WinForms project with 2 Forms, expecting a DialogResult whenever the child Form was shown to continue execution in my main Form.
var form2 = new ThisNameSpace.FormChild();
var dResult = form2.ShowDialog(this);
if(dResult == DialogResult.OK)
{
// Do some work
}
else
{
// Do other work
}
For some reason, I had to move the child Form in another project. I've referenced the new Project's dll in my main startup Form project but I'm now unable to return a dialog result. When my child Form closes the FormClosing event of the main Form is raised with CloseReason.None and the application exits. How can I work this around?
You should not raise FormClosing event yourself, and you should not write any custom code to just close the dialog.
Instead do this:
on your OK button in child form, set DialogResult property to OK
on your child form, set set Accept Button property to point to your OK button
that's all you need to close the window and correct DialogResult will be returned.
If you ever need to close it 'manually' (and this is rare for modal dialogs, i.e. those opened with ShowDialog instead of Show), use Close method.
I'm writing a Windows application that basically runs in the background with a notification icon to interact with it. The notification icon can do basic things like exit the application or show information about it. It can also launch a modal configuration dialog.
The code that creates the dialog is pretty straightforward:
using(var frmSettings = new SettingsForm(configuration))
{
frmSettings.ConfigurationChanged += ConfigurationChangedHandler;
frmSettings.UnhandledException += UnhandledExceptionHandler;
frmSettings.ShowDialog();
}
The SettingsForm class basically has three GroupBox controls, with a Label and TextBox control in each, and 4 Button controls at the bottom: "Advanced...", "Restore Defaults", "Cancel", and "Apply". Each TextBox has a Validating event handler wired up through the designer. Each button has a Click handler wired up through the designer. Each of them does pretty obvious things: opens another modal dialog with more advanced settings, restores the textboxes to their default values, closes the dialog, or saves the changes, fires the ConfigurationChanged event, and then closes the dialog (but only if all fields are valid!).
When there is a form entry error I cancel the corresponding Validating event by setting ((CancelEventArgs)e).Cancel = true. However, the default behavior of both forms was to prevent the user from changing focus when validation failed. I found this pretty annoying and eventually found the option in the designer to still automatically validate when the user leaves the field, but to allow them to leave even if validation fails: AutoValidate = EnableAllowFocusChange.[1]
My "Apply" button Click handler looks basically like this:
private void btnApply_Click(object sender, EventArgs e)
{
try
{
if(this.ValidateChildren())
{
this.Configuration.Field1 = this.txtField1.Text;
this.Configuration.Field2 = this.txtField2.Text;
this.Configuration.Field3 = this.txtField3.Text;
if(this.Configuration.Changed)
{
this.Configuration.Save();
this.OnConfigurationChanged(new ConfigurationChangedEventArgs(
this.Configuration));
}
this.Close();
}
}
catch(Exception ex)
{
this.OnUnhandledException(new UnhandledExceptionEventArgs(
"Failed To Apply Configuration Settings",
ex));
}
}
I'm currently testing out the code by breaking on the first line and stepping through the method line by line. Essentially, ValidateChildren is returning false as expected and the entire if block, including the this.Close() are skipped. Yet, if I step all the way to the bottom of the method and then step out of it I end up back on the frmSettingsForm.ShowDialog() line and the form is magically closed.
The "Apply" button is set as the form's AcceptButton. I wonder if it's implicitly attached a handler to the button's Click event to automatically close the form when the button is pressed. That doesn't sound like it logically should be assumed, especially considering there doesn't seem to be a way to cancel the Click event, but it's the only explanation that I can come up with. To test that theory, I have tried unsetting the AcceptButton in the designer, but my form still closes when the data is invalid.
What is closing my form and how do I stop it?
[1]: If anybody else has trouble finding it, it's a form property, not a property of each individual control (as I expected it would be).
Do you have the DialogResult of the Button set? If so, when you click the Button, the DialogResult of the Form will be set to that value and the modal Form will close. To prevent this, when validation fails in your Click handler, set the Form's DialogResult to DialogResult.None.
I don't know why that happens, but you could override the event OnFormClosing and check for the value of DialogResult according to your logic.
If (DialogResult != Windows.Forms.DialogResult.Cancel )
e.Cancel = True