How to correctly use ShowDialog method in this case? - c#

I have problem with Windows Forms.
When I show form2 from form1 like this (names of the variables changed):
form2.ShowDialog(form1);
then I have this exception:
System.InvalidOperationException: Form that is already visible cannot be displayed as a modal dialog
box. Set the form's visible property to false before calling showDialog.
Telling more - during debugging I see that after calling ShowDialog method debugger goes again to the same ShowDialog method - and this is why I have this exception. I suppose that form1 is loaded again and it is some kind of ShowDialog method bug? I have form2 Visible property set to false. I tried to use Hide method too - not working.
Edit:
More info - I use ShowDialog method after showing combo box selector from form1. When I click the last property in combo box by mouse - ShowDialog is working. If I go down by keyboard and click 'Enter' mentioned exception appears.

Try something like this. When you close Form2, control will go back to Form1 (or whoever called Form2):
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.ShowDialog();
}

Or just
private void button1_Click(object sender, EventArgs e)
{
new form2().ShowDialog();
}

Related

How does the Form.Modal property changes when using button in a form?

I'm using 2 forms in an application in which, clicking button in form1 opens form2. While opening form2, the Modal property of form2 is FALSE. But, once on clicking the button in form2, the value of this property is set to TRUE. I have used the below code in the application.
Form1
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
bool isModal = f2.Modal;
f2.ShowDialog();
}
Form2
private void button1_Click(object sender, EventArgs e)
{
bool isModal = this.Modal;
}
Kindly share your ideas on how this is updated?
Thanks,
Sindhu
The docs state:
Gets a value indicating whether this form is displayed modally.
The key word here is is.
Let's look at your code:
Form2 f2 = new Form2();
bool isModal = f2.Modal;
f2.ShowDialog();
The question you need to ask is "in that second line, is the form at that time shown modally?"
The answer is clearly No, since it is only shown modally on the third line. If you think logically, this makes perfect sense. The form doesn't know whether you are going to call Show or ShowDialog - so Modal can't tell you about the future - it can only tell you about the current state of affairs.
Thus, on the second line, Modal must (according to the docs) return false.
OK, so why is it true in here?
private void button1_Click(object sender, EventArgs e)
{
bool isModal = this.Modal;
}
Well, based on the docs we need to ask ourselves whether this is currently displayed modally when the button is clicked. Yes at that time it is, so it must (according to the docs) return true.
While it may appear to have something to do with the buttons, it does not. It has to do with ShowDialog(); method.
If you check before f2.ShowDialog();, the Modal will be false. Check after and it will be true.
This f2.ShowDialog(); is what sets the property to true.
You may use f2.Show() and it will stay false in this case for obvious reason.
As #CodingYoshi said, the method that is setting the Form.Modal to true is Form.ShowDialog(). This is why f2.Modal is false, because it is called before f2.ShowDialog().
The problem is checking the f2.Modal after calling f2.ShowDialog. The problem is that you cannot execute any further code lines in the code block after calling f2.ShowDialog(). Thus, there is no way to call f2.Modal.
The best way to see this difference to check Modal first in your constructor and then check it again in the Form.Load event. The constructor is called before ShowDialog is called, but Form.Load and Button.clicked are called after ShowDialog is called. Thus, you have different values for the Modal property.
Here the constructor of Form2:
Sub New ()
' This call is required by the designer.
InitializeComponent()
Console.WriteLine(Me.Modal) ' is always false
End Sub
And then Form.Loading event of Form2:
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Console.WriteLine(Me.Modal) ' will return true if object is called via ShowDialog()
End Sub

Why isn't the Validated event firing for controls on a form created in the main form when the child form is closed?

Say I have a winforms application with two forms, the main form that starts up when the program runs, and another form. Here is the code for the main form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.ShowDialog();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Main Form: Validated!");
}
}
And this is the child form:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Child Form: Validated!");
}
}
When I run the application, I can put the focus in the textbox on the main form, and of course when I tab out, it fires the Validated event and prints Main Form: Validated! to the output. This also happens if I have the focus in the textbox and close the main form (i.e. end the program).
When I click the button on the main form which pops up an instance of the child form, I can put the focus in the textbox on the child form, and the Validated event fires as it should when I tab out of it. However, unlike the main form behavior on closing the form, if I have the focus in the textbox on the child form and I close the child form, the Validated event never fires.
Why doesn't the validated event fire, and is there a way I can make it fire.
I'm relying on the validated event of certain controls to update my view models. I want to make sure they always fire even when the loss of focus is due to a form closing or even the application itself ending.
This is caused by ShowDialog(). It is a documented bug, a mistake in .NET 1.x that they could not fix anymore. From the Form.cs source code:
// NOTE: We should also check !Validate(true) below too in the modal case,
// but we cannot, because we didn't to this in Everett (bug), and doing so
// now would introduce a breaking change. User can always validate in the
// FormClosing event if they really need to. :-(
So just follow the guidance:
protected override void OnFormClosing(FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing && this.DialogResult != DialogResult.Cancel) {
if (!base.Validate(true)) e.Cancel = true;
}
base.OnFormClosing(e);
}
With the assumptions that you don't need the event when the dialog is dismissed and you'd want the dialog to stay open when validation fails. The latter clause is new behavior.
Documentation says:
Unlike non-modal forms, the Close method is not called by the .NET
Framework when the user clicks the close form 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.
Based on the docs, when you call the ShowDialog method of the second form (Form2) and you close it by clicking on the close button (the button with an X at the upper-right corner of the form) the form is hidden (not closed). This is why the Validated event never fires.
Note: Closing and Closed events will fire anyway.
Note2: Closing the form using ALT + F4 is the same as clicking on the X button of the form.
Demonstration
Form as modal (your example)
The second form is opened by calling ShowDialog.
Add a button on the second form and set the click event as follow:
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
If you close the form by clicking in that new button the Validated event will fire. If you close the form by clicking the button with an X at the upper-right corner of the form, the Validated event won't fire (because the form has never closed, it has been hidden).
Form as non-modal
The second form is opened by calling Show.
In this case, when you click the button with an X at the upper-right corner of the form the latter will be really closed (not hidden) and the Validated event fires.
Workaround
Hiding the ControlBox
The simplest method is to hide the X button of the form setting the ControlBox property to false (by designer or by code). However, the user could close the form using ALT + F4.
Using Hans Passant solution
Hope to be clear.
If you want, all your modal dialog controls validated, while closing .. probably you can approach below way.... which definitely fires the text box validated event.
Add an event for form closing in Form2 and call ValidateChildren()
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
this.ValidateChildren();
}
MSN Documentation
According to MSN Documentation If the CausesValidation property is set to false, the Validating and Validated events are suppressed.
Verifies the value of the control losing focus by causing the Validating and Validated events to occur :According to MSN Documentation
You can also fired Validating and Validated events by using Validate() method that lose the focus of controls. So you can call Validate method within closing event of Form2. Bellow is the code
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Child Form: Validated!");
}
private void Form2_Closing(object sender, FormClosingEventArgs e)
{
if (!Validate())
//Write your code that will execute if your form is not validated
}
}

change active form to show another form

I have a Form1 and another one that I added. Form1 is being run by program.cs at the start. I need to hide Form1 and show options form by the press of a button.
private void submitPassword_Click(object sender, EventArgs e)
{
options optionForm = new options();
optionForm.Show();
}
the above code opens the options form on top, but I need it to replace the current form. how can I achieve this?
Hide current form using this.Close() before showing new one and make sure you are using parameterless Application.Run so program won't close when you close it's main form.
You can use "Hide" and "Show" method :
private void submitPassword_Click(object sender, EventArgs e)
{
options optionForm = new options();
this.Hide();
optionForm.Show();
}
private void submitPassword_Click(object sender, EventArgs e)
{
options optionForm = new options();
optionForm.Show();
this.Hide();
}
Similar solutions where one form calls and acts on another... Such as this one I answered for another. You could do a similar process... pass in your first form to the second... Then show the second... Then, you could HIDE your first form (via this.Hide() ). Then, in your second form, when you click whatever button to select your choice, and need to return back to the first form, you could then use the original form's reference passed INTO the second form to re-Show it, such as in the click on the second form...
this.PreservedForm.Show(); // re-show original form
this.Close(); // and CLOSE this second form...

3 forms Show and ShowDialog not working as expected, BUG?

I am using Visual Studio 2010, C# .NET 4.0. I have 3 forms: Form1, Form2, Form3.
In Form1 I have a button to open Form2:
private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.Show();
}
In Form2 I have a private Form3 variable always pointing to the same Form3:
private Form3 f = new Form3();
And a button to open it as a dialog:
private void button1_Click(object sender, EventArgs e)
{
f.ShowDialog();
}
In Form3 I just have a button to hide the form:
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
}
The problem is that having the situation that Form2 is in front of Form1, and Form3 in front of Form2, when I click the button of Form3 to hide it, it not only hides itself but sends Form1 to the back of all of the other Windows.
This only happens when there is a window of another program (such as Windows Explorer) in the background of Form1. It seems like a bug. What do you think?
Yes, this cannot work properly by design. A dialog disables all of the windows that your program displays. So that it is modal. When you hide the dialog, there are no windows left that can get the focus. Windows is forced to find another window to give the focus to. That will be a window owned by another application. Your own windows will now hide behind it.
There are more side effects, the dialog will also close. Necessary because otherwise the user can never get back to your program anymore since all windows are disabled. This is all unsurprising behavior. Bug would be a strong word, but it would of course work better if it first re-enabled all windows before closing the dialog. But closing the dialog is already undesirable behavior.
Don't call Hide() for a dialog. Just set the DialogResult property to DialogResult.Cancel to achieve the exact same effect, minus the focus problem. You do have to reset it back to None if you want to display the dialog again. That's a real bug.
By the documentation. Form.Close method doesn't dispose forms shown by Form.ShowDialog method. Quote:
The two conditions when a form is not disposed on Close is when (1) it is part of a multiple-document interface (MDI) application, and the form is not visible; and (2) you have displayed the form using ShowDialog. In these cases, you will need to call Dispose manually to mark all of the form's controls for garbage collection.
So, maybe there are ways to return focus to your application (e.g. via Windows API). But it is much more convenient to call Form.Close manually on dialog windows.

ShowDialog() doesn't make the window modal

I have a windows form that pops up a dialog box if certian conditions are met when the form loads. The problem is the window does not stay on top and I can still click thing on the parent. However, there is a button on the form that when pressed opens the same window, when I do this it works as expected (like a dialog window).
Is there an issue with showing a dialog when a form is first loading?
Are you calling ShowDialog from the Form class? Because it will only set the parent window if called from another Form. Alternatively you can use the overload that has the IWin32Window parameter to specifically set the owner.
can you explain the issue further as this is my code which do not show the form it self until the dialog has been closed either you set the parent or not
private void Form1_Load(object sender, EventArgs e)
{
//your functionality goes here
AboutBox1 box = new AboutBox1();
box.ShowDialog();
}
}
on the other side you can also check with TopMost property
The ShowDialog method needs to be called from the form that you want to be it's parent/owner in order for it to be modal to that form. Alternatively I believe you can set the owner of a dialog directly but I have never needed to do that.
DaBomb,
To do what you want, you will have to call your modal dialog from the constructor of your main form, NOT from the Form_Load event.
Something like this:
public Form1()
{
InitializeComponent();
this.Show();
Form2 popupForm = new Form2();
popupForm.ShowDialog();
}

Categories

Resources