Click here to Skip to main content
15,889,877 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everyone,
i have multiform project, and there is an event, when this event is fired a new form is supposed to open, now if i close this form and try to reopen it one more time, the compiler complains "cannot access a disposed object".

after some trials, i managed to figured it out but i would like to know if my solution is poor and if there is some better one

C#
if (newgame_form.IsDisposed)
{
    newgame_form = new new_game();
    newgame_form.Show();
}
else
    newgame_form.Show();


Note newgame_form is declared as global new_game form
C#
new_game newgame_form = new new_game();


Thanks in advance,
z3ngew
Posted

This solution is ok.

However, if you want to use just a single instance of a form, you can actually store the form in a dictionary (once loaded) then display it as and when required.
 
Share this answer
 
Comments
z3ngew 25-Aug-13 6:38am    
would you please give me a code snippet for that,
thanks for your effort,
z3ngew
Abhinav S 25-Aug-13 12:06pm    
Dictionary<string,form> o = new Dictionary<string,form>();
o.add("form1",o);
There are two scenarios possible here:

1. when the user (or you, in your code) closes a given Form: you don't need to retain any of the current information on that Form. Where "information" could mean: what is selected in a Form's various Controls, what is entered in a Form's various TextBoxes, etc.

Great, use Dispose.

Then, you must recreate that Form, when you need it again, as Madonna sang: "Like a virgin, for the very first time."

2. when you want to 'hide a Form, and then, show it again, presumably because you want to retain the information in the Form: just use FormX.Hide(); or FormX.Visible = 'false;

~

As my respected colleague Abhinav S's answer points out, there are a number of ways you could keep track of which Forms are currently "alive;" the technique he proposed is using a Dictionary.

But, keep in mind that, at any moment at run-time in Windows Forms: Application.OpenForms supplies you with a List of (what else ?) currently open Forms (where open means "visible".

Unfortunately, it's not a List that supports operators like 'Contains, or useful Linq operators. You'd have to enumerate Application.OpenForms every time you wanted to see if a given Form Type was open (really, not such a big deal)

~

So, is there another systematic way to keep track of all the open Forms, and their visual state, shown, or hidden: well, I believe a slight variation on Abhinav's Dictionary concept may be useful:

1. define a Dictionary of type <FormInstance, bool>

2. when you dispose of a Form, remove it from the Dictionary.

3. when you create a new instance of a Form: add it to the Dictionary, add a new KeyValuePair, with the Form as Key, and set the boolean Value of the KeyValuePair to 'true if it is visible, and 'false if it is not.

4. when you change the visual state of a Form, but are not disposing it: set the boolean Value of the KeyValuePair of which the Form is the Key to its changed visual state.

How, then, is this Dictionary to be updated to reflect changes in the "state" of the Forms contained as Keys: when a Form is closed, when it's hidden, when it exists, but is hidden, and you, or the user, want to make it visible again ? How to handle adding another new Form, and "registering" it with the Dictionary, and making sure it, too, updates the Dictionary when its "state" changes ?

If the Form that creates the Dictionary (presumably your Main Form) also creates the other Forms being used, then, at the moment they are created, you can wire-up their VisibleChanged, and FormClosed Events to EventHandlers defined in your main Form.
How might this look in code:
C#
// the dictionary of instances of Forms, and a boolean
// that will indicate their visual state
// true = shown
// false = hidden
private Dictionary<Form, bool> dictActiveForms = new Dictionary<Form, bool>();

// for convenience
private Form changingForm;

// note that the Form instances created inside
// the scope of this Form Load EventHandler
// are "gone" after it's been called, and the only
// access available is through the 'dictActiveForms

// also note that we did not include the Main Form
// instance itself in the Dictionary we 'fill-up' here
private void MainForm_Load(object sender, EventArgs e)
{
    Form2 instanceOfForm2 = new Form2();
    instanceOfForm2.Text = "the original Form2 instance";
    dictActiveForms.Add(instanceOfForm2, true);
    instanceOfForm2.Show();

    // no duplicate key error because we are using
    // Instances of Forms as Keys, not Form "Types"
    Form2 anotherInstanceOfForm2 = new Form2();
    anotherInstanceOfForm2.Text = "the second Form2 instance";
    // note this one's not visible, yet
    dictActiveForms.Add(anotherInstanceOfForm2, false);

    Form3 instanceOfForm3 = new Form3();
    instanceOfForm3.Text = "the one-and-only Form3 instance";
    dictActiveForms.Add(instanceOfForm3, true);
    instanceOfForm3.Show();

    // wire up the Event for all the Forms
    // we've created and put in the Dictionary
    wireAllFormEvents();
}

private void wireFormEvents(Form theForm)
{
    theForm.VisibleChanged += TheFormOnVisibleChanged;
    theForm.Closed += TheFormOnClosed;
}

private void wireAllFormEvents()
{
    // now let's wire the Events up for every Form
    foreach (Form theForm in dictActiveForms.Keys)
    {
        wireFormEvents(theForm);
    }
}

private void TheFormOnVisibleChanged(object sender, EventArgs eventArgs)
{
    changingForm = sender as Form;

    dictActiveForms[changingForm] = changingForm.Visible;
}

private void TheFormOnClosed(object sender, EventArgs eventArgs)
{
    changingForm = sender as Form;

    dictActiveForms.Remove(changingForm);
}
Using this as a basis, let's consider what happens if the user (or you, the programmer, in your code) wants to now make visible the second instance of Type Form2 created above. For demonstration purposes we'll define this in a Button's Click EventHandler:
C#
private void button1_Click(object sender, EventArgs e)
{
    // we could use Linq here, and note we are not
    // checking here to make sure a second instance
    // of Form2 still exists: even though no error
    // will be thrown here if it doesn't;
    // keep in mind this is just a demo
    foreach (Form theForm in dictActiveForms.Keys)
    {
        if (theForm.Text == "the second Form2 instance";
        {
            if (dictActiveForms[theForm] == false) theForm.Visible = true;
            break;
        }
    }
}
How you might add, at run-time, a new Form instance of a Type you want, and "do the right thing" to make it behave like the other "secondary" Forms created here in the Form Load Event:
C#
private void addNewForm(Type formType, string formText, bool isFormVisible)
{
    Form newForm = (Form) Activator.CreateInstance(formType);
    newForm.Text = formText;
    dictActiveForms.Add(newForm, isFormVisible);
    wireFormEvents(newForm);
    newForm.Visible = isFormVisible;
}
A call to this method could look like this (once again, for demo purposes, we'll put it in a Button's Click EventHandler):
C#
private void button2_Click(object sender, EventArgs e)
{
    addNewForm(typeof(Form3), "another instance of Form3", true);
}
Discussion: this is "only one way to fly" when managing multiple Forms created by a Main Form in WinForms, and providing for multiple Forms to be added dynamically (at run-time). The code here is completely tested, but is written-out in fairly elaborate form for educational reasons, only.

In many cases you will know in advance exactly how many secondary Forms your main Form may need, and that doesn't vary, and you can reduce the complexity of the code shown here by simply keeping references around to each secondary Form. And, in many cases, you will not need to allow the user to create multiple new instances of secondary Forms at run-time.

imho, where things get really interesting is where you create multiple independent Forms by modifying the normal behavior of WinForms apps ("running" a single "main" form instance in the Program.cs file) ... but that's another story.

Hope you find some useful "bits" in the code here.

edit ... for anyone wants to play with the working code for what's shown here, compiled against FrameWork 2.0, so, hopefully everyone an use it: [^].
 
Share this answer
 
v4

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