【问题标题】:How to avoid Multiple Child forms shown in MDIParent C# Win Forms如何避免在 MDIParent C# Win Forms 中显示多个子窗体
【发布时间】:2011-07-12 04:16:36
【问题描述】:

当用户尝试打开已在 MDIParent 中打开的子表单时,我想避免我的子表单多次出现。避免这种情况的一种方法是禁用控制器(在我的情况下为 BUTTON),但我也为此功能提供了快捷键 (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();

    }

我想避免这种情况。我怎样才能做到这一点?

在图像中,您可以看到子表单名称 Online Leads 被打开了两次,因为用户第一次使用菜单 (LEADS) 打开,第二次使用快捷键打开。我不希望这种情况发生。如果表单已经打开,它应该避免打开另一个相同的表单......如何做到这一点?

【问题讨论】:

    标签: c# winforms mdichild mdiparent


    【解决方案1】:

    如果我只应该打开一个,我通常会这样做:

    //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();
    }
    

    【讨论】:

      【解决方案2】:

      在你的表单 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();
      

      【讨论】:

        【解决方案3】:

        我个人更喜欢通用的实现:

        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 泛型。我很想知道使用反射是否有任何明显的额外开销;尽管处于非常高的水平。
        • 我想任何额外的开销都可以忽略不计。它仅在您尝试打开表单时运行,因此除非您同时打开大量表单,否则我无法想象它会对您的应用程序性能或用户体验产生任何影响。
        • 那很好。我想在一个可扩展的应用程序中,无论如何你都会使用你的 IoC 容器,而不是依赖 Activator。我现在已经在 RadDock 中使用了这种方法,以跟踪 MDI Children 和 Tool Windows。我已将Show()Activate() 取出,并将原始表单作为T 类型返回,以便它可以停靠在需要的地方。
        • 不错。很酷的解决方案。感谢您的反馈。很高兴我可以分享其他人可以使用的东西:)
        【解决方案4】:
        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。我只能重复关闭和打开一个表单。
        • 我正在使用 .net 3.5 和 VS 2010 Ultimate,Windows Xp ..这是 cousing 错误
        【解决方案5】:
            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;
           }
        

        【讨论】:

          【解决方案6】:

          从菜单打开表单的第一个时间,变量frmRep为空

          frmReportes frmRep = null
          

          ...所以我在第一个“if”中添加另一个“if”来验证我的表单是否可见,因为我有另一个表单,那么如果它不可见,我会创建一个实例并显示表单,但 if 是可见的我只是使用激活()

              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();
                  }            
              }
          

          【讨论】:

            【解决方案7】:

            最简单的方法是保留对子表单的引用,并且仅在它不存在时才生成一个新表单。像这样的:

            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 设置 formWeblead =null 将使用 Child 的 Event 留给父访问,可以吗? ???或者有什么最好的方法吗
            • 我不认为我会使用 Leaving 事件,因为这是一个焦点事件。相反,使用子表单的 Closing 事件,当您关闭它时触发。
            • @Mike 这留下了一些关于调用点击事件的菜单项的 TODO;我喜欢禁用创建表单的菜单项以避免用户混淆,例如“我正在点击‘打开’,但没有任何反应”。
            • @Gangelo:嗯,当然。但这超出了问题的范围。不难弄清楚在哪里插入.Enabled = false.Enabled = true 代码。或者,更好的是formWeblead.Focus() 代码。
            【解决方案8】:
            // Implementation of the below class in your MDI Parent
            private void openToolStripMenuItem_Click(object sender, EventArgs e) {
                        if (SingletonForm.Exists) {
                            return;
                        } else {
                            m_openToolStripMenuItem.Enabled = false;
            
                            SingletonForm form = new SingletonForm();
                            form.FormClosed += new FormClosedEventHandler(
                                delegate(object _sender, FormClosedEventArgs _e) {
                                    m_openToolStripMenuItem.Enabled = true;
                                });
                            form.MdiParent = this;              
                            form.Show();
                        }
                    }
            
            
            // SingletonForm Class
                using ...
                using System.Threading;
            
                namespace SingletonForm {
            
                    public partial class SingletonForm : Form, IDisposable {
                        static private readonly string m_mutexName = "SingletonForm.SingletonForm";
                        private Mutex m_mutex;
                        private bool m_disposed;
            
                        public SingletonForm() {
                            m_disposed = false;
            
                            // Check to see if there is already a running instance...
                            bool owned;
                            m_mutex = new Mutex(true, m_mutexName, out owned);
                            if (!owned) {
                                // Already running, get out...
                                Close();
                                return;
                            }
            
                            InitializeComponent();
                        }
            
                        ~SingletonForm() {
                            Dispose(false);
                        }
            
                        static public bool Exists {
                            get {
                                bool owned;
                                using (new Mutex(false, m_mutexName, out owned)) {
                                    return !owned;
                                }
                            }
                        }
            
                        // IDisposable Members
                        // --------------------------------------------------------------------------
                        #region IDisposable Members
                        new public void Dispose() {
                            Dispose(true);
            
                            // Use SupressFinalize in case a subclass of this type implements a finalizer.
                            GC.SuppressFinalize(this);
                        }
                        #endregion  // IDisposable Members
            
                        /// <summary>
                        /// Note: Comment out the Dispose(bool disposing) implementation in your
                        /// SingletonForm.Designer.cs
                        /// </summary>
                        /// <param name="disposing">true if we are disposing.</param>
                        protected override void Dispose(bool disposing) {
                            if (disposing && (components != null)) {
                                components.Dispose();
                            }
            
                            base.Dispose(disposing);
            
                            // If you need thread safety, use a lock around these 
                            // operations, as well as in your methods that use the resource.
                            if (!m_disposed) {
                                if (disposing) {
                                    // Code to dispose the managed resources held by the class here...
                                    if (m_mutex != null) {
                                        m_mutex.Dispose();
                                        m_mutex = null;
                                    }
                                }
            
                                // Indicate that the instance has been disposed.
                                m_disposed = true;
                            }
                        }
                    };
                };
            

            如果使用信号量来允许存在 1-n 个实例会很好。

            【讨论】:

              【解决方案9】:

              这是我为调用创建的“方法”,当您单击 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();
                  }
              }
              

              【讨论】:

                【解决方案10】:

                您可以检查当前打开的表单来实现:

                if (Application.OpenForms.Count == 1) {
                    ReportProductDetails Report9 = new ReportProductDetails();
                    Report9.MdiParent = this;
                    Report9.Show();
                    Report9.Activate();
                }
                else {
                    MessageBox.Show("Sorry!Close the All the Exist Form,Before open this Form", "Information", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                

                【讨论】:

                  【解决方案11】:

                  我用这个解决方案,有点小技巧

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

                  【讨论】:

                    【解决方案12】:
                        private void mnuMyForm_Click(object sender, EventArgs e) // click to open MyForm
                        {
                            foreach (Form item in this.MdiChildren) // check all opened forms
                            {
                                if (item.Name == "MyFormName") // check by form name if it's opened
                                {
                                    item.BringToFront(); // bring it front
                                    return; //exit
                                }
                            }
                    
                            // if MyForm is not opened
                            // you know what it is
                            MyForm frm = new MyForm();
                            frm.MdiParent = this;
                            frm.Show();
                        }
                    

                    【讨论】:

                      【解决方案13】:

                      防止MDI表单中出现相同子表单的代码

                      private void materialToolStripMenuItem_Click(object sender, EventArgs e)
                      {
                        frmMaterial newMDIChild = new frmMaterial();
                        bool opened = false;
                        foreach (Form OpenForm in Application.OpenForms)
                        {
                          if (OpenForm.GetType() == typeof(frmMaterial))
                          {
                            OpenForm.Activate();//to bring the activated form to the front
                            opened = true;
                          }
                        }
                        if (opened==false)
                        {
                          // Set the Parent Form of the Child window.
                          newMDIChild.MdiParent = this;
                          //newMDIChild.WindowState = System.Windows.Forms.FormWindowState.Maximized;
                          // Display the new form.
                          newMDIChild.Show();
                        }
                      }
                      

                      【讨论】:

                        【解决方案14】:

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

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

                        然后这样称呼它:

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

                        【讨论】:

                          【解决方案15】:

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

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

                          【讨论】:

                            猜你喜欢
                            • 2010-11-27
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2010-10-31
                            • 2018-09-02
                            • 1970-01-01
                            • 2016-11-12
                            • 1970-01-01
                            相关资源
                            最近更新 更多