I am using .NET 3.5 with c# winforms. in this i am using MDI child tab control. it works fine if i open a form, it will open successfully. if i open same form again it opens. that means duplication of tabs.
My code is like below...
private void Main_MdiChildActivate(object sender, EventArgs e)
{
if (this.ActiveMdiChild == null)
tabForms.Visible = false; // If no any child form, hide tabControl
else
{
this.ActiveMdiChild.WindowState = FormWindowState.Maximized; // Child form always maximized
if (this.ActiveMdiChild.Tag == null)
{
TabPage tp = new TabPage(this.ActiveMdiChild.Text);
tp.Tag = this.ActiveMdiChild;
tp.Parent = tabForms;
tabForms.SelectedTab = tp;
this.ActiveMdiChild.Tag = tp;
this.ActiveMdiChild.FormClosed += new FormClosedEventHandler(ActiveMdiChild_FormClosed);
}
if (!tabForms.Visible) tabForms.Visible = true;
}
}
in this, every time this.ActiveMdiChild.Tag takes the value of null so it opens new form again and again. that means duplication of forms in tab control
Add the above method in order to check if the form with the name is as child in the mdi parent.
public static bool FormExist(string formName, out Form frm)
{
frm = null;
bool exist = false;
Form[] f = yourMdiParent.ActiveForm.MdiChildren;
foreach (Form ff in f)
{
if (ff.Name == formName)
{
frm = ff;
exist = true;
break;
}
}
return exist;
}
and add the check on adding the child form.
Form forma;
if(FormExist("yourchildformid",out forma) && forma !=null)
{
forma.Focus();
return;
}
I'm late to the party, but I use:
private void serviceManagerToolStripMenuItem_Click(object sender, EventArgs e)
{
// prevent duplicates
if (Application.OpenForms.OfType<ServiceManager>().FirstOrDefault() != null)
{
return;
}
ServiceManager serviceManager = new ServiceManager { MdiParent = this, WindowState = FormWindowState.Maximized };
serviceManager.Show();
}
I was able to get this to work with a few tweeks by combining other solutions
add this function to your Parent MDI Form
private bool checkTabExists(string tabVal)
{
foreach (TabPage tab in tabForms.TabPages)
{
if (tab.Text == tabVal)
return true;
}
return false;
}
Then Modify the original Form_MdiChildActivate to include an additional check
private void Main_MdiChildActivate(object sender, EventArgs e)
{
if (this.ActiveMdiChild == null)
tabForms.Visible = false; // If no any child form, hide tabControl
else
{
this.ActiveMdiChild.WindowState = FormWindowState.Maximized; // Child form always maximized
if(checkTabExists(this.ActiveMdiChild.Name))
{
//If the Child Form already Exists Go to it
foreach (TabPage tab in tabForms.TabPages)
{
if (tab.Text == this.ActiveMdiChild.Name)
tabForms.SelectedTab = tab;
}
}
// If child form is new and has no tabPage, create new tabPage
else if (this.ActiveMdiChild.Tag == null)
{
ActiveMdiChild.TopLevel = false;
ActiveMdiChild.Dock = DockStyle.Fill;
ActiveMdiChild.FormBorderStyle = FormBorderStyle.None;
// Add a tabPage to tabControl with child form caption
TabPage tp = new TabPage(this.ActiveMdiChild.Text);
tp.Tag = this.ActiveMdiChild;
tp.Parent = tabForms;
tabForms.SelectedTab = tp;
this.ActiveMdiChild.Tag = tp;
this.ActiveMdiChild.FormClosed += new FormClosedEventHandler(Main_FormClosed);
}
if (!tabForms.Visible) tabForms.Visible = true;
//tabForms.AutoSize = true;
//tabForms.TabPages[0].Height = 38;
}
}
Related
I have a form. I want to make sure that the RegisterForm.cs form comes as childform when the toggle button I added on this form is activated. It works in a different position from the main panel when I call it normally. Whatever I've done, I haven't been able to solve this problem, can you help me with that?
FormMainMenu.cs
public void OpenChildForm(Form childForm)
{
if (currentChildForm != null)
{
//open only form
currentChildForm.Close();
}
currentChildForm = childForm;
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
panelDesktop.Controls.Add(childForm);
panelDesktop.Tag = childForm;
childForm.BringToFront();
childForm.Show();
lblTitleChildForm.Text = childForm.Text;
}
SozlesmeFormu.cs
public partial class SozlesmeFormu : Form
{
private bool toggleCheck = false;
public SozlesmeFormu()
{
InitializeComponent();
textBox1.Multiline = true;
textBox1.ScrollBars = ScrollBars.Both;
}
private void toggleSozlesme_CheckedChanged(object sender, EventArgs e)
{
toggleCheck = true;
toggleSozlesme.Enabled = false;
toggleSozlesme.OnBackColor = Color.DarkGray;
this.Close();
FormMainMenu formMain = new FormMainMenu();
formMain.OpenChildForm(new RegisterForm());
}
}
Whatever I did, I couldn't call RegisterForm as childform. It's always irrelevant from the main panel.
I have an MDI form in which I create two MDIChild forms, cf1 and cf2.
I have a button which, when clicked, should toggle the "focus" (i.e. which form is "on top") between cf1 and cf2.
In the constructor of the MDI parent, I assign the MDIParent of the respective cf1 and cf2. Then I execute cf1.Show() then cf2.Show(), thus cf2 ends up "on top" or "focused."
When I press the toggle button the first time, cf1 becomes focused and cf2 becomes inactive.
Any further attempts to change the z-order after this are unsuccessful.
I have tried Activate, ActivateMdiChild, TopMost and BringToFront, all without success.
using System;
using System.Windows.Forms;
namespace MDITest
{
public partial class Form1 : Form
{
private readonly ChildForm cf1 = new ChildForm();
private readonly ChildForm cf2 = new ChildForm();
public Form1()
{
InitializeComponent();
cf1.MdiParent = this;
cf2.MdiParent = this;
cf1.Text = "Window 1";
cf2.Text = "Window 2";
cf1.Show();
cf2.Show();
}
private void Child_WMSize(object sender, EventArgs e)
{
LblWindow1State.Text = $"Window 1 - {cf1.WindowState.ToString()}";
LblWindow2State.Text = $"Window 2 = {cf2.WindowState.ToString()}";
}
private void BtnFocus_Click(object sender, EventArgs e)
{
//if (ActiveMdiChild == cf1) cf2.Activate();
//if (ActiveMdiChild == cf2) cf1.Activate();
//if (ActiveMdiChild == cf1) ActivateMdiChild(cf2);
//if (ActiveMdiChild == cf2) ActivateMdiChild(cf1);
//if (ActiveMdiChild == cf1) cf2.TopMost = true;
//if (ActiveMdiChild == cf2) cf1.TopMost = true;
if (ActiveMdiChild == cf1) cf2.BringToFront();
if (ActiveMdiChild == cf2) cf1.BringToFront();
}
}
}
The expected result would be to toggle the focus between the two forms as needed. The actual result is that I can only change from cf2 to cf1, not the other way around.
I even tried the shotgun approach:
if (ActiveMdiChild == cf1)
{
cf2.BringToFront();
cf2.Activate();
ActivateMdiChild(cf2);
cf2.TopMost = true;
cf1.TopMost = false;
}
if (ActiveMdiChild == cf2)
{
cf1.BringToFront();
cf1.Activate();
ActivateMdiChild(cf1);
cf1.TopMost = true;
cf2.TopMost = false;
}
With no change in my results.
You can use the following code to toggle between any number of Mdi children windows:
if (MdiChildren.Length == 0)
return;
var i = Array.IndexOf(MdiChildren, ActiveMdiChild);
MdiChildren[(MdiChildren.Length + i + 1) % MdiChildren.Length].Activate();
Or
this.Controls.OfType<MdiClient>().First()
.SelectNextControl(ActiveMdiChild, true,true, true, true);
Or
SendKeys.SendWait("^{TAB}"); // Control + TAB as well as Control + F6
I'm designing a Windows Form to create a child form at run time. I would like that the child form build controls (buttons, list boxes, etc.) depending on a the text entered in the parent form. My problem is when I close the child form, enter new text and relaunch the child form, the same control is being created.
This is how I call the child form:
private void button2_Click(object sender, EventArgs e)
{
try
{
Form2 frm2 = new Form2();
frm2.Show();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This is the code in the child form
try
{
this.MaximizeBox = false;
this.MinimizeBox = false;
this.BackColor = Color.White;
this.ForeColor = Color.Black;
this.Size = new System.Drawing.Size(550, 550);
this.Text = "Test Create form in run time ";
Form1 frm1 = new Form1();
if (frm1.master == "button")
{
this.btnAdd.BackColor = Color.Gray;
this.btnAdd.Text = "Add";
this.btnAdd.Location = new System.Drawing.Point(90, 25);
this.btnAdd.Size = new System.Drawing.Size(50, 25);
this.Controls.Add(btn);
}
}
Can anyone give me a piece of code or link ?
The problem is that you are not sending the text from From1, instead you are creating a new Form1 inside Form2. This is not what you want I guess...
To solve this:
Add a String property in Form2, called say 'ControlText'.
Suppose that the user write the text in a text box called Text1 in
Form1
Then you would call form2 from Form1 like this:
private void button2_Click(object sender, EventArgs e)
{
try
{
Form2 frm2 = new Form2();
frm2.ControlText = Text1.text
frm2.Show();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Finally, the code in form2 will be something like this:
try
{
this.MaximizeBox = false;
this.MinimizeBox = false;
this.BackColor = Color.White;
this.ForeColor = Color.Black;
this.Size = new System.Drawing.Size(550, 550);
this.Text = "Test Create form in run time ";
if (ControlText == "button")
{
this.btnAdd.BackColor = Color.Gray;
this.btnAdd.Text = "Add";
this.btnAdd.Location = new System.Drawing.Point(90, 25);
this.btnAdd.Size = new System.Drawing.Size(50, 25);
this.Controls.Add(btn);
}
}
hope this may help you
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Utilities.ResetAllControls(this);
}
public class Utilities
{
public static void ResetAllControls(Control form)
{
foreach (Control control in form.Controls)
{
if (control is TextBox)
{
TextBox textBox = (TextBox)control;
textBox.Text = null;
}
if (control is ComboBox)
{
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
}
if (control is CheckBox)
{
CheckBox checkBox = (CheckBox)control;
checkBox.Checked = false;
}
if (control is ListBox)
{
ListBox listBox = (ListBox)control;
listBox.ClearSelected();
}
}
}
}
Try this
foreach(control in this.Controls)
{
this.Controls.Remove(control);
control.Dispose();
}
this.Controls.Clear();
this is my problem: I have a main form where I have a panel that contains some buttons, when the user clicks a button a form is opened.( I have some buttons and clicking these buttons the user can open different forms )If the user click again the same button he can close the form.
this is what I do:
in the main form I have a method that is invoked when one of these buttons is clicked by the user, the method checks the text associated to the button in order to decide which is the button clicked. Once I have discovered which is the button that has been clicked it launches the form associated with the button.
this is the code
private void tlStBtn_Click(object sender, EventArgs e)
{
//// loop through all items in the ToolStrip
//foreach (Object item in toolStripMain.Items)
//{
// // if this item is a ToolStripButton object, check it
// if (item is ToolStripButton)
// {
// // cast the item to a ToolStripButton object and check it if the sender of the event is the currently looked at button in the loop
// ToolStripButton button = (ToolStripButton)item;
// button.Checked = (button == sender);
// }
//}
foreach (ToolStripItem item in this.VerticalToolBox.Items)
{
if ((item != sender) &&
(item is ToolStripButton))
{
((ToolStripButton)item).Checked = false;
}
}
if (sender_old != sender)
{
sender_old = sender;
if ((sender as ToolStripButton).Text == "Protection")
{
if (!Application.OpenForms.OfType<frm_Protection>().Any())
{
frm_Protection Newf = new frm_Protection(ref CurrentProject);
Newf.Show();
}
}
else
{
if (Application.OpenForms.OfType<frm_Protection>().Any())
{
Application.OpenForms.OfType<frm_Protection>().First().Close();
Properties.Settings.Default.Save();
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
if ((sender as ToolStripButton).Text == "Info")
{
if (!Application.OpenForms.OfType<Frm_ObjectInfo>().Any())
{
Frm_ObjectInfo Newform = new Frm_ObjectInfo();
Newform.Show();
}
}
else
{
if (Application.OpenForms.OfType<Frm_ObjectInfo>().Any())
{
Application.OpenForms.OfType<Frm_ObjectInfo>().First().Close();
Properties.Settings.Default.Save();
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
if ((sender as ToolStripButton).Text == "Layers")
{
if (!Application.OpenForms.OfType<Frm_LayersManage>().Any())
{
Frm_LayersManage Newform = new Frm_LayersManage();
Newform.Show();
Application.OpenForms.OfType<Frm_LayersManage>().First().UpdateLayers(null, CurrentProject.layers);
}
}
else
{
if (Application.OpenForms.OfType<Frm_LayersManage>().Any())
{
Application.OpenForms.OfType<Frm_LayersManage>().First().Close();
Properties.Settings.Default.Save();
UpdateScreen = true;
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
if (Properties.Settings.Default.Grip2Enabled && (sender as ToolStripButton).Text == "Insert Grip")
{
gbx_SelectGrip.Visible = true;
}
else
{
gbx_SelectGrip.Visible = false;
}
//SelectedPoints.Clear();
//MousePointList.Clear();
//myIDs.Clear();
//IdxPointsEnt.Clear();
//RatiosLines.Clear();
//CadSource.cuts_tmp.Clear();
//IDAddedCutList.Clear();
//ZoomPort.SetValue(0, 0);
//ZoomPort.SetValue(0, 1);
//ZoomPort.SetValue(0, 2);
//ZoomPort.SetValue(0, 3);
//// Reset index of scrap selected by moving gripper
//idxScrap = -1;
//pnl_OpenTK.Refresh();
//// Se ho evidenziato uno SCRAP , annullo l'evidenziazione.
//if (IdsScrapDisablePath[0] != -1)
//{
// int identifiedScrap = CadSource.IdToIdx_Scrap(IdsScrapDisablePath[0]);
// if (CadSource.scraps[identifiedScrap].GripExists())
// {
// CadSource.scraps[identifiedScrap].Enabled = ScrapAbilitation.Enabled; // Disable clicked scrap
// }
// else
// {
// CadSource.scraps[identifiedScrap].Enabled = ScrapAbilitation.WithoutGrip; // Disable clicked scrap
// }
//}
//numScrap = 0;
//IdsScrapDisablePath = new List<int>() { -1, -1 };
}
else
{
(sender as ToolStripButton).Checked = false;
(sender as ToolStripButton).BackColor = Color.Transparent;
sender_old = new object() { };
if (Application.OpenForms.OfType<frm_Protection>().Any())
{
Application.OpenForms.OfType<frm_Protection>().First().Close();
Properties.Settings.Default.Save();
}
if (Application.OpenForms.OfType<Frm_ObjectInfo>().Any())
{
Application.OpenForms.OfType<Frm_ObjectInfo>().First().Close();
Properties.Settings.Default.Save();
}
if (Application.OpenForms.OfType<Frm_LayersManage>().Any())
{
Application.OpenForms.OfType<Frm_LayersManage>().First().Close();
Properties.Settings.Default.Save();
}
gbx_SelectGrip.Visible = false;
GC.Collect();
GC.WaitForPendingFinalizers();
}
SelectedPoints.Clear();
MousePointList.Clear();
myIDs.Clear();
IdxPointsEnt.Clear();
RatiosLines.Clear();
CurrentProject.cuts_tmp.Clear();
IDAddedCutList.Clear();
ZoomPort.SetValue(0, 0);
ZoomPort.SetValue(0, 1);
ZoomPort.SetValue(0, 2);
ZoomPort.SetValue(0, 3);
// Reset index of scrap selected by moving gripper
idxScrap = -1;
pnl_OpenTK.Refresh();
// Se ho evidenziato uno SCRAP , annullo l'evidenziazione.
if (IdsScrapDisablePath[0] != -1)
{
int identifiedScrap = CurrentProject.IdToIdx_Scrap(IdsScrapDisablePath[0]);
if (CurrentProject.scraps[identifiedScrap].GripExists())
{
CurrentProject.scraps[identifiedScrap].Enabled = ScrapAbilitation.Enabled; // Disable clicked scrap
}
else
{
CurrentProject.scraps[identifiedScrap].Enabled = ScrapAbilitation.WithoutGrip; // Disable clicked scrap
}
}
numScrap = 0;
IdsScrapDisablePath = new List<int>() { -1, -1 };
}
the forms that are opned clicking the buttons are forms where I have set the controlbox at false because I don't want that the user is able to close the forms without clicking again the button that has clicked to open it, but I have found a problem because if the user closes the form in this way (see the picture below) the status of the button remains checked but the form has been closed manually
To solve this problem I have thought to add this method associated to the event closing of my forms this is the code
private void frm_Protection_FormClosed(object sender, FormClosedEventArgs e)
{
////// if user closes manually the window without using the button I have to change the state of the button
Frm_Main f = new Frm_Main();
f = Application.OpenForms.OfType<Frm_Main>().Last();
f.tlsBut_Protection.Checked = false;
}
with this code if I close manually the form the status of the button it becomes false again in the main form
but I have discovered that It causes some problems to my program , one of this problem is that after closing the form if I click again the button it seems that the method associated to the clicking event is not called and the form is not opened I have to click it twice before it works again.
do you know why what do I do in the wrong way???
thanks for your help
To prevent a Form from closing, you can subscribe to the FormClosing event, which fires before the Form closes, and intercept (and cancel) the user's action.
private void frm_Protection_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
e.Cancel = true;
}
Unfortunately, clicking the "X" (in the Taskbar preview or in the program itself) and calling this.Close() are both treated as "UserClosing" close reasons, so we need to modify it slightly.
Add a property to frm_Protection, and use that to determine whether the Form can be closed:
public bool CanClose { private get; set; }
private void frm_Protection_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = !CanClose;
}
And then only set the property to true when you want to allow the Form to be closed:
var frmP = Application.OpenForms.OfType<frm_Protection>().FirstOrDefault();
if (frmP != null)
{
frmP.CanClose = true;
frmP.Close();
}
Some forms I want to be loaded only once by the MDI Parent. So, in the click event of the menuitem, I look to see if the MDI parent's .Children property already contains the form and the form is loaded only if it is not already among the children:
bool alreadyLoaded = false;
if (this.MdiChildren.Length > 0)
{
foreach (Form frm in this.MdiChildren)
{
if (frm.Name == "foo")
{
alreadyLoaded=true;
break;
}
}
}
if (! alreadyLoaded)
{
FOO f = new FOO();
f.MdiParent=this;
f.Show();
}
But if the impatient user clicks rapidly on the menu item the very first time the form is loaded, it can be loaded more than once. The second and third clicks on the menu item launch a new copy of the form before the instance loaded by the first click is fully instantiated.
I suppose I could maintain my own list of launched form names and, in the menuitem's click eventhandler, add the form's name to the list if it isn't already there, and later remove it from the list in the child form's Closed eventhandler. But is there a better way?
Try out this class:
/// <summary>
/// Displays form in mdi form once
/// </summary>
/// <autor>Saber Amani</autor>
/// <lastUpdate>2009-03-03</lastUpdate>
public class MdiFormDisplayer
{
private Hashtable fForms = new Hashtable();
private object fSender = null;
public MdiFormDisplayer(object sender)
{
fSender = sender;
}
public Form GetForm(Type formType)
{
string formName = formType.Name;
Form frm = (Form)fForms[formName];
if (frm == null || frm.IsDisposed)
{
frm = CreateNewInstance(formType);
fForms[formName] = frm;
}
return frm;
}
public Form GetForm(string formName)
{
if (fSender == null)
throw new ArgumentNullException("Sender", "Sender can't be null");
return GetForm(fSender, formName);
}
public Form GetForm(object sender, string formName)
{
Form frm = (Form)fForms[formName];
if (frm == null || frm.IsDisposed)
{
frm = CreateNewInstance(sender, formName);
fForms[formName] = frm;
}
return frm;
}
private Form CreateNewInstance(object sender, string formName)
{
Type frmType;
frmType = FindFormType(sender, formName);
Form frmInstance = (Form)CallTypeConstructor(frmType);
return frmInstance;
}
private Form CreateNewInstance(Type frmType)
{
Form frmInstance = (Form)CallTypeConstructor(frmType);
return frmInstance;
}
private Type FindFormType(object sender, string formName)
{
Type baseType = sender.GetType();
Assembly senderAssembly = Assembly.GetAssembly(baseType);
Type result = null;
// Search with assembly standard method
result = senderAssembly.GetType(baseType.Namespace + "." + formName);
if (result != null)
return result;
// Search with in the types
Type[] assemblyTypes = senderAssembly.GetTypes();
formName = formName.ToLower();
for (int i = 0; i < assemblyTypes.Length; i++)
{
if (assemblyTypes[i].Name.ToLower() == formName)
return assemblyTypes[i];
}
return null;
}
private object CallTypeConstructor(Type frmType)
{
Type[] contructTypes = new Type[] { };
ConstructorInfo constructorObj = frmType.GetConstructor(contructTypes);
object result = constructorObj.Invoke(null);
return result;
}
}
use like this :
public partial class frmMainForm : Form
{
MdiFormDisplayer forms;
public frmMainForm()
{
InitializeComponent();
forms = new MdiFormDisplayer(this);
}
private void btnCompany_Click(object sender, EventArgs e)
{
Form frm = forms.GetForm(typeof(frmCompany));
frm.MdiParent = this;
frm.Show();
frm.Focus();
}
}
Hope this help.
a simple flag that you set when the menu handler is called - called something like "processingClick". If this flag is already set, just quit the handler. Remember to reset it to false at the end of the routine.
Alternatively you could put a big critical section around the contents of the menu handler - so if its click twice in rapid succession, the 2nd click will wait for the 1st one to be handled. That guarantees that your 1st click gets to do all its processing.
you could disable the menu item on first click directly before instatiating the respective form... and on closing the form you could reenable the menu item... this way the user can't do what you describe...