如何避免在C# Win Forms的MDIParent中显示多个子窗体

8

我希望在用户尝试打开已经在MDIParent中打开的子窗体时,避免我的孩子出现多次。避免这种情况的一种方法是禁用控制器(在我的情况下是按钮),但我也为此功能提供了快捷键(Ctrl+L)。因此,如果用户键入Ctrl+L,相同的子窗体将打开,我可以看到MDI中有两个子窗体。

private void leadsToolStripMenuItem_Click(object sender, EventArgs e)
    {
        frmWebLeads formWeblead = new frmWebLeads();
        formWeblead.MdiParent = this;
        formWeblead.WindowState = System.Windows.Forms.FormWindowState.Maximized;
        formWeblead.Show();

    }

我想避免这种情况。我该怎么做? enter image description here 在图片中,您可以看到一个名为“Online Leads”的子表单被打开了两次,因为用户第一次使用菜单(LEADS)打开,第二次使用快捷键打开。我不希望发生这种情况。如果表单已经打开,则应避免再次打开相同的表单...如何做到这一点?
15个回答

4

如果我只允许打开一个,我通常这样做:


//class member for the only formWeblead
frmWebLeads formWebLead = null;

private void leadsToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (formWebLead == null)
    {
        formWeblead = new frmWebLeads();
        formWeblead.MdiParent = this;
    }

    formWeblead.WindowState = System.Windows.Forms.FormWindowState.Maximized;
    formWeblead.Show();
}

4

在你的表单main()函数中设置这个

    InitializeComponent();
     this.WindowState = FormWindowState.Maximized;
     this.ShowInTaskbar = true;

 from_login login = new from_login();
                login.MdiParent=this;
                login.Show();
                pmsnrr.pmsmain = this;  

这是要放在菜单条漂亮事件中的代码:

if (this.ActiveMdiChild != null)
            this.ActiveMdiChild.Close();
            frm_companymaster company = new frm_companymaster();
            company.MdiParent = this;
            company.WindowState = FormWindowState.Normal;
            company.Show();

4
我个人更喜欢通用实现:
private void ShowOrActivateForm<T>() where T : Form
        {
            var k = MdiChildren.Where(c => c.GetType() == typeof(T)).FirstOrDefault();
            if (k == null) 
            {                    

                k = (Form)Activator.CreateInstance(typeof(T));
                k.MdiParent = this;
                k.Show();
            }
            else
            {
                k.Activate();                
            }            
        }

那么你可以像这样使用它:
ShowOrActivateForm<myForm>();

在这里,myForm是您想创建的表单的类型。


我喜欢这种方法。它比为每个子元素创建空字段要可扩展得多。泛型加1分。我很想知道使用反射是否会有任何明显的额外开销,尽管在非常高的层面上。 - Apache
1
我想任何额外的开销都是可以忽略不计的。它只在尝试打开表单时运行,所以除非您同时打开大量表单,否则我无法想象它会对您的应用程序性能或用户体验产生任何影响。 - Dave Coates
很好。我想在可扩展的应用程序中,您将使用IoC容器,而不是依赖于“Activator”。我现在已经使用了这种方法来跟踪MDI子窗口和工具窗口的RadDock。我已经将“Show()”和“Activate()”移除,并将原始表单作为类型“T”返回,以便可以将其停靠在需要的位置。 - Apache
1
很好,很棒的解决方案。感谢反馈。很高兴能分享一些有用的东西 :) - Dave Coates

3
private void leadsToolStripMenuItem_Click(object sender, EventArgs e)
{
    formWeblead formWeblead = null;
    if ((formWeblead = IsFormAlreadyOpen(typeof(frmWebLeads)) == null)
    {
        formWeblead = new frmWebLeads();
        formWeblead.MdiParent = this;
        formWeblead.WindowState = System.Windows.Forms.FormWindowState.Maximized;
        formWeblead.Show();
    }
}

public static Form IsFormAlreadyOpen(Type FormType)
{
   foreach (Form OpenForm in Application.OpenForms)
   {
      if (OpenForm.GetType() == FormType)
         return OpenForm;
   }

   return null;
}

对不起,我没有遇到同样的问题。我正在使用VS 2008上的.NET 3.5。我可以重复关闭和打开一个窗体。 - Joe
我正在使用 .NET 3.5 和 VS 2010 Ultimate,Windows XP... 这会导致错误吗? - panindra

2
    frmWebLeads formWeblead;

    bool isformWebleadOpen =false;

    private void leadsToolStripMenuItem_Click(object sender, EventArgs e)
    {
      if(isformWebleadOpen == false)
      {
       formWeblead = new frmWebLeads();
       isformWebleadOpen =true;
       formWeblead.Closed += formWeblead_Closed;
       formWeblead.Show();
      }
   }

   void formWeblead_Closed(object sender, EventArgs e)
   {
     isformWebleadOpen = false;
   }

1

当您从菜单打开表单时,变量frmRep为空。

frmReportes frmRep = null

因此,我在第一个“if”语句中添加了另一个“if”语句来验证我的表单是否可见,因为我有其他表单,如果它不可见,我会创建一个实例并显示该表单,但是如果它可见,我只需使用Activate()

    private void rToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (frmRep != null)
        {
            if (frmRep.Visible == false)
            {
                frmRep = new frmReportes();
                frmRep.MdiParent = this; frmRep.Show();
            }
            else
            {                    
                frmRep.Activate();
                return;
            }
        }
        else
        {
            frmRep = new frmReportes();
            frmRep.MdiParent = this; 
            frmRep.Show();
        }            
    }

0
这是我为在MDIParent中单击菜单时仅调用一个表单而创建的“方法”。希望这个“方法”能够帮到你!
使用方法:在ToolStripMenuItems上触发。
Form1 frm1 = new Form1();
CheckActiveChildForm(frm1,"myForm");

//myForm is the Text of Form1
private void CheckActiveChildForm(Form FormControl, string FormExists)
{
    int h = 0;
    if (MdiChildren.Count() == 0)
    {
        //Form2 childF = new Form2();
        FormControl.MdiParent = this;
        FormControl.Show();
    }

    if (MdiChildren.Count() > 0)
    {
        for (int i = 0; i < MdiChildren.Count(); i++)
        {
            if (MdiChildren.ElementAt(i).Text == FormExists)
            {
                h = 1;
            }
        }
    }

    if (h == 0)
    {
        FormControl.MdiParent = this;
        FormControl.Show();
    }
}

0

防止子进程多实例化的最简单方法

private void Showforms(Form frm)
{
    if (this.ActiveMdiChild==null)
    {
        frm.MdiParent = this;
        frm.Show();
    }  
}

0

防止多个子实例的最简单方法:

 private void Showforms(Form frm)
 {
   if (this.ActiveMdiChild==null)
   {
      frm.MdiParent = this;               
      frm.Show();
   }
 }

然后像这样调用它:

Form1 frm = new Form1();
Showforms(frm);

0
最简单的方法是保留对子窗体的引用,仅在不存在时才生成新的窗体。类似这样的代码:
class ParentForm : Form { 
    frmWebLeads formWeblead = null;

    //...

    private void leadsToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if(formWeblead != null) return;
        formWeblead = new frmWebLeads();
        formWeblead.MdiParent = this;
        formWeblead.WindowState = System.Windows.Forms.FormWindowState.Maximized;
        formWeblead.Show();

    }

}

当你关闭它时,你还需要编写代码将formWeblead设置为null,但我相信你可以解决这一部分 :)


@ Mike Caron,感谢您的代码。您留给我的最后一部分让我有些困惑,在MDIParent中声明的formWeblead,我考虑使用frmWebLoad将其设置为null,并在子事件中访问父级,这样可以吗!!???还是有更好的方法可用? - panindra
1
我认为我不会使用 Leaving 事件,因为那是一个焦点的问题。相反,使用子窗体的 Closing 事件,当你关闭它时会触发该事件。 - Mike Caron
@Mike 这里还有一些关于调用点击事件的菜单项需要处理;我想禁用创建该表单的菜单项,以避免用户混淆,例如“我点击‘打开’但没有反应”。 - gangelo
@Gangelo:当然可以,但这已超出问题的范围。插入“.Enabled = false”和“.Enabled = true”代码并不难。甚至更好的方法是插入“formWeblead.Focus()”代码。 - Mike Caron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接