Click here to Skip to main content
15,887,596 members
Please Sign up or sign in to vote.
1.67/5 (3 votes)
See more:
hi every body, i use dynamically toolstripmenu to generate menu, i don't know how to prevent form open twice, please help.

this is my code :
C#
ToolStripMenuItem SubMenu = new ToolStripMenuItem(sdr1["description"].ToString(), null, new EventHandler(klikMenu));

private void klikMenu(object sender, EventArgs e)
        {
            string sFormName = "AIO_System." + ((ToolStripMenuItem)sender).Tag.ToString();
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

            Form frm = (Form)asm.CreateInstance(sFormName);    <======
            if(!IsFormOpen(frm.GetType()))
                {
                    frm.Owner = this;
                    frm.Show();
                }
                else
                    frm.Focus();
            }
        }

        private bool IsFormOpen(Type formType)
        {
            foreach (Form form in Application.OpenForms)
                if (form.GetType().Name == form.Name)
                    return true;
            return false;
        }
Posted
Updated 24-Oct-20 3:07am
v2
Comments
BillWoodruff 24-Feb-14 22:43pm    
This is a repost of a question asked 11 hours before this post which has had several helpful answers:

http://www.codeproject.com/Messages/4765814/how-to-prevent-form-open-twice.aspx

First of all, this is not a good question: 1) there is no such thing as "open a form", even though you can "close" a form; 2) you show the form, so it should be obvious that it's up to you to decide what to open and what's not; you cannot ask questions every time you have to decide on something as trivial as that; if you asked how to do it nicely, it would be a different story.

So, in development of second item above, you can use lazy initialization pattern, or, load on call, which is probably the best in such cases: http://en.wikipedia.org/wiki/Lazy_initialization#C.23[^].

In a very simple form, you should just encapsulate the method of showing the form:
C#
class SomeForm : Form { // for example, your main form;
                        // this class does not have to be a form...

    void ShowOneMoreForm() {
        if (oneMoreForm == null) {
            oneMoreForm = new OneMoreForm.Create();
            //...
            oneMoreForm.Owner = this; // very important item
            //..
        } //if
        oneMoreForm.Show();
    } //ShowOneMoreForm

    OneMoreForm oneMoreForm; // initialized as null

} //class SomeForm
Simple, isn't it?

This guarantees that you have only one form of this type, and that it preserve its state (because you never created it second time). Sometimes, this approach solve much more complex problem: some operations in the implementation of ShowOneMoreForm cannot be performed to early, for example, in its constructor, or when the main form is not properly setup. Sometimes it is hard to find out appropriate moment for this. And in this load-on-call solution, you only create and setup this form when it is really required for the very first time, say, when the user needs to work with it.

—SA
 
Share this answer
 
v4
Comments
[no name] 25-Feb-14 12:05pm    
Hi Sergey;
You offer good, general advice - but your solution ignores an OP requirement that the form be created by reflection. The toolstrip definition was included to show that the class name of the form couldn't be determined until run-time. I'd go further and speculate the toolstrip contained multiple submenus like this one. It would be nice to declare a type specific variable for each form but I don't see how that would be possible if introspection (eg. determined by dynamic plugin, table, or configuration file) is required.
Sergey Alexandrovich Kryukov 25-Feb-14 12:12pm    
"Created by reflection" should be part of requirements. Development should be consistent. If some document is a set of requirements specifying what should be implemented (behavior), it should not specify "how". Breaking such simple principle would be a sure way of blocking development.

Anyway, I cannot see how my solution prevents using reflection... And I don't see anything telling that the class name (name??? of class itself? But then it is solved using OOP) is not determined before runtime. "Type-specific variable" for each form can be dirty style of programming. Again, something similar can be done using OOP, or OOP with interfaces...

Anyway, my solution is quite easy generalized to the polymorphic set of form types, can't you see it? My code sample is needed just to conduct the idea.

—SA
[no name] 26-Feb-14 14:26pm    
Your idea is clear but leaves open numerous possibilities. I'm curious, how you would make use of this solution from the klikMenu method?
Sergey Alexandrovich Kryukov 26-Feb-14 14:49pm    
It depends on the set of form types. In most extreme general case, when all the concrete forms are totally unknown at compile time, they have to be give something known at compile type. The best approach is this: you make them all implementing some interface (plug-in interface, I call it). Then the host application gets some assembly, in extreme general case, not known during compile time, so it will be loaded during runtime. Then, with reflection, you find all types implementing this interface and perform instantiation of those forms. I do even better; I also define assembly-level attribute used to claim what types should be considered as plug-in implementation, it cuts the search down (for example, to no search at all). And then we use the interface. The plug-in forms have some identifier (name, description) which goes to the menu of the host application. When menu is activated, the appropriate form is found among plug-ins. (It's good to use the dictionary to hold all the references to them.)

Please understand, it all has nothing to do with this question itself, goes well beyond it. The problem is just the moment of invocation. If OP has some concerns, let him ask some follow-up questions.

—SA
[no name] 26-Feb-14 14:51pm    
Awesome. Thanks Sergey!
Don't create the form until after you verified it's not already open.


private void klikMenu(object sender, EventArgs e)
{
string sFormName = "AIO_System." + ((ToolStripMenuItem)sender).Tag.ToString();
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

Form activate = null;
foreach (Form frm in System.Application.OpenForms)
{
if (frm.Name == sFormName)
{
activate = frm;
break;
}
}
if (activate == null)
{
activate = (Form)asm.CreateInstance(sFormName);
activate.Owner = this;
activate.Show();
}
else
activate.Focus();
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900