Click here to Skip to main content
15,949,686 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to understand collections and have to admit I'm really struggling with it. I have seen many examples where variables are added to an arraylist. I am trying to build a PostIT note application (there will be people saying "is he still doing that!!!") and collections are the way forward. I mocked up a very quick application to test creating a new form and adding it an Arraylist.



C#
namespace test2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public ArrayList test = new ArrayList();

        private void btnAdd_Click(object sender, EventArgs e)
        {
            test.Add(new Form2());
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            test.RemoveAt(0);
        }
    }
}


And Form2 just has 'this.Show();' in the Form2 constructor to display itself. I'll save space by not posting the code in it.

The code creates a Form2 object whenever I click the 'Add' button which is good. Its the 'Remove' button that I need help with. Just for testing, I am removing the first object from the Arraylist with each press. I am checking the number of objects stored in test and it is indeed decreasing as it should. I expected that removing the object from Arraylist would also remove the object itself.

I am guessing that removing the object for arraylist just removes the pointer to it so I need to also close the form. Is an event raised that I should use or is there a better way? Please bear in mind that I am trying to teach myself and have quite a limited knowledge so simpler the better please.
Posted

In the Remove method, you can very well get the form instance, close it and then remove it from the ArrayList. And just to be type safe, you can use a List<Form> instead of an ArrayList.
 
Share this answer
 
v2
Suppose you use test.RemoveAt(0) it will just remove from the Arraylist.

If you want to close that form then use following code:
((Form)test[0]).Dispose();

if you want to show that form then use Show() instead of Dispose.

Try this, Hope it will work for you.

Regards!
Aman
 
Share this answer
 
Comments
Jim607 17-Aug-11 9:16am    
Is ((Form)test[(test.Count - 1)]).Show(); an OK method to reference the form after it has been created or is there a better way?
BobJanova 17-Aug-11 11:06am    
Once you're using a List<Form>, you don't need to cast and more:
test[(test.Count - 1)]).Show();
... is a reasonable way to show the last form, imo.
Solutions 1 and 2 correctly solve your immediate problem. I want to be more general about collections.

As you've surmised, removing an item from a collection does not destroy that item – .Net collections do not 'take ownership' of items you put into them. This is generally a good thing, as you will have references elsewhere and those should remain valid (and if you don't, the item will go out of scope anyway and be destroyed in a GC cycle). However, with UI elements, the framework maintains references to them so they don't go out of scope and your application can lose track of them.

If you use a list class which implements INotifyCollectionChanged (i.e. ObservableCollection<Form>) or IBindingList (e.g. BindingList<T>), there is an event when the collection is changed. But for List<T> (what you should use by default for typed extensible lists like this), there are no events.

In this case I would recommend switching the logic. Closing the form should remove it from the collection (you can't do anything with it anyway), which you can do by hooking onto the form's FormClosed[^] event:
List<Form> test = new List<Form>();

void Add(){
 Form2 form2 = new Form2();
 form2.FormClosed += (s,e) => test.Remove((Form)sender);
}


Then, you can cause a form to be removed by closing it, which will cause FormClosed to fire (if the close is allowed to happen) and thus the form to be removed from the list:
void RemoveFirst(){
 test[0].Close();
}
 
Share this answer
 
Comments
Jim607 17-Aug-11 10:23am    
This forum is brilliant! Thanks so much for your help and advice (to all who posted).
Jim607 17-Aug-11 16:51pm    
This would work great but I am getting a runtime error when I implement this. I am using a foreach loop to close all of the open forms but as the close event triggers, it alters the list. This is causing an error because the list has changed whilst doing the ForEach. Is there a way round this or should I just use a simple do loop instead?
lukeer 18-Aug-11 2:44am    
Either use a backward for loop
for(int i = formList.Count - 1; i >= 0; i--) formList[i].Dispose();
or repeatedly delete the first item
while(formList.Count > 0) formList[0].Dispose();
In case its useful for anybody else, here is my revised code after the very helpful answers I received.

public List<Form> test = new List<Form>();

private void btnAdd_Click(object sender, EventArgs e)
{
	test.Add(new Form2());
}

private void btnRemove_Click(object sender, EventArgs e)
{
	((Form)test[0]).Dispose();
	test.RemoveAt(0);
}
 
Share this answer
 
Hi, Some ideas to keep in mind, and perhaps explore in the context of your solution:

1. a WinForms Application exposes two Collections of type 'Form' which may be useful to you:

a. Application.OpenForms is a read-only Property of the Application which returns a FormCollection of all 'open' Forms.

b. #anyForm.OwnedForms is a read-only Property of any currently open Form which returns Form[] ... an array of Forms 'owned' by the 'Owner' Form.

2. consider, in a Post-It type scenario, assuming each Post-It Note is a separate Form, the difference between:

a. Closing the Post-It Form: the Form object is disposed, automatically: the Application.OpenForms collection is modified, and if the closed Form is 'owned' then its Owner Form's OwnedForms collection is updated. Any 'data' on the Form is lost unless you've saved it, and, if you want to display again: you have to call 'Show to use it.

b. Hiding a Post-It Form: the Form object is not disposed, it's data is not lost, it's still present in relevant collection of Application and/or OwnedForms. Make it 'visible' again any time you like.

3. If you run a WinForms app the usual way ... where the Program.cs file containing the 'Main static method runs an instance of a Form ... then you can rely on the fact that any other Forms created at run-time can be closed without terminating your Application.

You can also rely on the fact that closing your Main Form will close all other open Forms created in code.

All of this is independent of whether any Forms are 'visible' or not. So, you could have a scenario where your 'Post-It' Manager ... main Form ... was hidden, and if the user closed all the open Post-It Forms ... how would the user then have a way to get the 'Manager' form visible again ?

I leave this 'problem' for your imagination to handle using the information in this post :)

best, Bill

p.s. of the several books I've read on WinForms, Matthew MacDonald's book was excellent; if you are coming from a COM and C++ background into WinForms then I recommend Chris Sell's book.
 
Share this answer
 
v3

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