I have multiple form but for now only 2. A main one which gets loaded on app lunch and the other appears when the use select it from the side menu. The problem is that if the user clicks again on the menu, it creates a new form instead of keeping the same one. Something happens if they change form.
Here is the current code that handles the Click event.
private Form activeForm = null;
private void openChildForm(Form childForm)
{
if (activeForm != null)
{
activeForm.Close();
}
activeForm = childForm;
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
this.panelChildForm.Controls.Add(childForm);
this.panelChildForm.Tag = childForm;
childForm.BringToFront();
childForm.Show();
}
private void btnFalderon_Terminal_Click(object sender, EventArgs e)
{
openChildForm(new FalderonTerminal());
}
So, what modification I would have to make to my code for it to understand and check if the form is already open and displays the same one, so I don't louse the information on it. Like in this case the Serial Connection being made on the "FalderonTerminal" form.
UPDATE: So I made some changes to the condition where it look if the form is already open. But it seem's that it's alway creating a new form instead of using the old one :/
private void btnFalderon_Terminal_Click(object sender, EventArgs e)
{
if (Application.OpenForms.OfType<FalderonTerminal>().Any())
{
Application.OpenForms.OfType<FalderonTerminal>().First().BringToFront();
System.Diagnostics.Debug.WriteLine("Old Falderon Terminal");
}
else
{
System.Diagnostics.Debug.WriteLine("New Falderon Terminal");
openChildForm(new FalderonTerminal());
}
}
CodePudding user response:
If the form is not null and not IsDisposed
, you should be able to just show it. The problem with this code is that closing it will cause it to dispose. In that case (IsDispose || Disposing
) new to create a new copy (childForm = new ChildForm()
), which will start you over with a clean form.
CodePudding user response:
You should be aware about the difference between a modal dialog box and a modeless dialog box. The kind of dialog box influences how you should use it in your main form.
Modal dialog box
A modal dialog box is closed before the operator can use the main form. As long as the modal dialog box is shown the user input events of the main form are not called.
The structure of usage of this is similar to the following. Example of a file save as modal dialog box In your main form:
public void OnMenuFileSaveAs_Clicked(object sender, ...)
{
this.FileSaveAs();
}
And FileSaveAs:
public void FileSaveAs()
{
using (SaveFileDialog dialog = new SaveFileDialog())
{
// if needed set some properties of SaveFileDialog
dialog.Title = "File Save As";
dialog.InitialDirectory = ...
dialog.AddExtension = ...
// Show the dialog and wait until the operator is finished
DialogResult dlgResult = dialog.ShowDialog(this);
switch (dlgResult)
{
case DialogResult.Ok:
// operator selected a file name
string fileName = dialog.FileName;
this.SaveFileAs(fileName);
break;
case DialogResult.Cancel:
// operator cancelled file save as
this.CancelSaveFileAs();
break;
// etc.
}
}
}
The Modal dialog box only exists during this method. As long as the modal dialog box is not closed, the main form is not accessible.
Modeless dialog box
You want to show a Modeless dialog box. While this dialog box is shown, the operator can still handle the main form. This means that your return from the event handler in the main form before the modeless dialog box is closed. Therefore you should remember the modeless dialog box.
While the modeless dialog box is not closed, everything that makes it possible to open de modeless dialog box again should be disabled.
A nice method for this, would be to disable (gray out), the buttons and the menu items that can open this dialog box. A second method would be to leave the controls enabled, and to put focus on the modeless dialog box when the control (button / menu item) is clicked.
private MyModelessDialog ModelessDialog {get; set} = null;
private bool IsModelessDialogShown => this.ModelessDialog != null;
public void OnMenuShowModelessClicked(object sender, ...)
{
// only open the modeless dialog box if not shown yet
if (!this.IsModelessDialogShown)
{
// if desired, make sure that the menu item is disabled
this.DisableMenuItemShowModeless();
this.ShowModelessDialogBox();
}
else
{
// either do nothing, or decide to give the focus to the modeless dialog box
this.SetFocusOnModelessDialogBox();
}
}
private void DisableMenuItemShowModeless()
{
this.menuItemShowModeless.Enabled = false;
// is there also a button? Disable this as well
}
private void EnableMenuItemShowModeless()
{
this.menuItemShowModeless.Enabled = true;
// is there also a button? Enable this as well
}
You can give the modeless dialog box focus by using control.Focus()
. How this is done properly is out of scope of this question.
private void ShowModelessDialogBox()
{
// Create a new modeless dialog box object, and set some properties
this.ModelessDialogBox = new MyModelessDialogBox()
{
...
}
// make sure I get called when the modeless dialog box closes
this.ModelessDialogBox.Closed = this.ModelessDialogBox_Closed;
// Show the modeless dialog box as a modeless dialog box:
this.ModelessDialogBox.Show(this);
}
The modeless dialog box is shown. The operator can handle both the modeless dialog box as well as the main form. The menu item is disabled, so the operator can't click on it. If you chose not to disable it, and you click on it, no new modal dialog box is shown. The model dialog box gets the focus.
When the dialog box is closed, your main form gets notified:
private void ModelessDialogBox_Closed(object sender, EventArgs e)
{
if (Object.ReferenceEquals(sender, this.ModelessDialogBox)
{
this.ModelessDialogBox_Closed();
}
}
private void ModelessDialogBox_Closed()
{
// if needed read and process properties of the modeless DialogBox
this.ProcessModelessDialogBoxResults(this.ModelessDialogBox);
this.ModelessDialogBox -= ModelessDialogBox_Closed;
this.ModelessDialogBox.Dispose();
this.ModelessDialogBox = null;
this.EnableMenuItemShowModelesss();
}
Because I disabled the menu items that show a new modeless dialog box, Only one box will be shown. If you chose not to disable the menu item, then clicking it will set the focus on the modeless dialog box.
One last remark: did you notice that I use a lot of small procedures instead of doing everything in a few procedures. This prepares your program for changes, for instance if you decide to add a button instead of only a menu item. Of if you need to disable several menu items. Or if you decide in future versions not to disable the menu items anymore. Small procedures also make reuse and unit testing easier.
Be aware, if you close your main window while the modeless dialog box is still shown, the modeless dialog box is closed, because its Parent is closed. Everything is handled nicely, except that the operator has no chance to react on the result of the modeless dialog box. If you don't want this, subscribe your main form on IsClosing event and check IsModelessDialogBoxShown. If so, decide what to do: cancel closing? Warn the operator about the open dialog box?