【问题标题】:user's impatient multiple clicks on menuitem loads MDI child form multiple times用户不耐烦的多次点击 menuitem 多次加载 MDI 子窗体
【发布时间】:2011-07-25 16:34:40
【问题描述】:

我希望 MDI 父级仅加载一次某些表单。因此,在 menuitem 的单击事件中,我查看 MDI 父级的 .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();
            }

但是如果不耐烦的用户在第一次加载表单时快速单击菜单项,则可以多次加载它。在第一次单击加载的实例完全实例化之前,第二次和第三次单击菜单项会启动表单的新副本。

我想我可以维护我自己的已启动表单名称列表,并在菜单项的单击事件处理程序中,将表单名称添加到列表中(如果它尚不存在),然后将其从子表单的已关闭列表中删除事件处理程序。但是有没有更好的方法?

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    试试这个课程:

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

    这样使用:

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

    希望对您有所帮助。

    【讨论】:

    • 谢谢。这是一种比其他人建议的方法和我想到的方法更复杂的方法,在这种方法中,我的父 MDI 表单保留自己的已启动子项列表,并且子表单的名称被插入到 menuitem 的单击处理程序中的该列表中,并且子窗体负责在关闭时从该列表中删除自己的名称。但是,您将如何处理采用不同数量参数的重载表单构造函数?
    【解决方案2】:

    在调用菜单处理程序时设置的简单标志 - 称为“processingClick”之类的东西。如果此标志已设置,只需退出处理程序。请记住在例程结束时将其重置为 false。

    或者,您可以在菜单处理程序的内容周围放置一个重要的关键部分 - 因此,如果它快速连续单击两次,第二次单击将等待第一次处理。这保证了您的第一次点击可以完成所有处理。

    【讨论】:

    • 是否有可能在它加载的子窗体完全实例化之前到达 menuitem 的点击处理程序的末尾?
    【解决方案3】:

    您可以在启用相应表单之前直接在第一次单击时禁用菜单项...关闭表单时您可以重新启用菜单项...这样用户就无法执行您描述的操作...

    【讨论】:

    • 谢谢。我采用了类似的方法,子窗体负责通知父窗体它已关闭。但我不能禁用菜单项,因为它需要保持启用状态,以便在它已经打开但在其他表单后面时将打开的表单置于前面。
    猜你喜欢
    • 2016-12-27
    • 2016-02-02
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    • 2014-12-11
    • 2014-06-25
    • 2020-03-16
    • 1970-01-01
    相关资源
    最近更新 更多