Removing Closed Form from a List in C# - c#

So, i have a question on using a list of forms and when a form closes, to remove itself from the list in C#. I don't think the garbage collector does it automatically, right?
Let's say I have:
List<SomeGraphForm> GraphGroup = new List<SomeGraphForm>();
....
add the forms...
GraphGroup.Add(x);
When x closes, what is the cleanest way to remove it from the list? Is using FormClosed event the best way (but I am not sure how to pass SomeGraphForm item back to the other class(es)).

Right, the GC cannot collect something that is still referred to. I would go with this basic approach:
//code to create and add form
var form = new Form1();
form.FormClosed +=form_FormClosed;
_forms.Add(form);
form.Show();
//cleanup
private void form_FormClosed(object sender, FormClosedEventArgs e)
{
var closedForm = sender as Form1;
_forms.Remove(closedForm);
}

If you have a base class that you use to derive all forms from, you can unregister in the OnClosed method.
protected override void OnClosed(EventArgs e)
{
// unregister here
}

Related

Closing forms opened by this form

I'm writing a chat application for a school project. One of the forms I have is the Contacts form, from which I open different SingleDialogue forms (they are the 1 on 1 chats). I want to make it so that when I close the Contacts form, it closes all the SingleDialogue forms I have opened.
For this I made it so that the Contacts_FormClosing event triggers the Disconnected event in my client object, and in the Contacts form I made a method:
private void On_ImDisconnected(object sender, EventArgs e)
{
foreach (SingleDialogue sd in singleChats)
sd.Close();
}
singleChats is the name of a list of SingleDialogue forms opened from the Contacts form. Every time I open another SingleDialogue, it's added to singleChats.
And in the constructor I subscribed it to the Disconnected event in the client object:
im.Disconnected += new EventHandler(On_ImDisconnected);
So far, what should happen is that when I trigger the Disconnected event in the client object On_ImDisconnected fires up and closes all the SingleDialogues, correct?
But I get an exception saying "Cross-thread operation not valid: Control 'SingleDialogue' accessed from a thread other than the thread it was created on".
Alright, then I changed On_ImDisconnected:
private void On_ImDisconnected(object sender, EventArgs e)
{
this.BeginInvoke(new MethodInvoker(delegate
{
foreach (SingleDialogue sd in singleChats)
sd.Close();
}));
}
But now nothing happens. Can you guys help me solve this?
EDIT:
Declaration of the list:
List<SingleDialogue> singleChats = new List<SingleDialogue>();
Adding new members:
private void chatButton_Click(object sender, EventArgs e)
{
SingleDialogue sd = new SingleDialogue(im, chatTextBox.Text);
singleChats.Add(sd);
chatTextBox.Text = "";
sd.Show();
}
I'd say skip the list completely. In the constructor of your SingleDialogue Form you could add a handler to when the passed parent disconnects, and then close the SingleDialogue from within itself.
So if I had to guess what the constructor looks like, you could do something like this:
public SingleDialogue(<someFormType> im, string stringThingy)
{
...some initialization code...
im.Disconnected += new EventHandler(im_Disconnected); //Subscribe to the parent's Disconnected event.
}
private void im_Disconnected(object sender, EventArgs e) //When the parent disconnects.
{
if(this.InvokeRequired) { this.Invoke(() => this.Close()); }
else { this.Close(); }
}
Note that I'm not a native C# developer, so if I did something wrong please tell me. :)
As I understood the scenario, you're keeping a list of forms in Contact form and want to close it.
I suppose your approach is wrong, when you're subscribing every form to the Disconnected event. Why not close the form on event trigger from inside of it?
You just need this code in your every SingleDialogue instance:
//subscribe to event handler, most probably in constructor
im.Disconnected += new EventHandler(On_ImDisconnected);
//close on event fire
private void On_ImDisconnected(object sender, EventArgs e)
{
this.Close();
}
You don't need to go through the list and close the forms from a parent form.
If I got the question wrong, please correct me.

Best way to handle passing of Control.Checked state between forms

It's been a while since I've worked with Windows Forms applications. I have a Checkbox on the Main form and, based upon a certain condition, if the Second form needs to be opened to request additional data from the user, how should I pass (or get) back a message to the Main form from the Second form so I can tell whether or not it's okay to Check or Uncheck the Checkbox?
From what I can remember, I could use something like Pass by ref. Or is there a better way to accomplish this?
Since you are showing the child form as a dialog, and the parent form doesn't need it until the form as closed, all you need to do is add a property with a public getter and private setter to the child form, set the value in the child form whenever it's appropriate, and then read the value from the main form after the call to ShowDialog.
One way to do this would be to use an event.
In your child form, declare an event to be raised upon specific user interaction, and simply "subscribe" to this event in your main form.
When you instantiate and call you child form, you'd do like this:
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.MyEvent += frm_MyEvent;
frm.ShowDialog();
frm.MyEvent -= frm_MyEvent;
}
private void frm_MyEvent(object sender, EventArgs e)
{
textBox1.Text = "whatever"; //just for demo purposes
}
In your child form, you declare the event and raise it:
public event EventHandler MyEvent;
private void button1_Click(object sender, EventArgs e)
{
if (MyEvent!= null)
MyEvent(this, EventArgs.Empty);
}
Hope this helps

Re-open child form

I have one Main form and two types of child form
MainForm
ChildFormA - unique
ChildFormB - have multiple forms of this type
I create ChildFormA with:
ChildFormA form1 = new ChildFormA();
form1.MdiParent = this;
form1.Show();
But when i close it with:
form1.Close();
I can't re-open it.
I've already read some tips that I can Hide this form instead or closing it. But the X button still closes the form.
How to re-open or how to prevent the X button to close and simple hide it?
If you want your child form to remain in its state, you have to subscribe to the FormClosing event and set the Cancel property of the event argument to true.
public ChildForm()
{
...
FormClosing += new FormClosingEventHandler(ChildForm_FormClosing);
}
void ChildForm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
Keep in mind, that you're form will not get disposed, if you don't add more logic to this.
Otherwise, you can just create a new instance of it.
Create a new instance of ChildFormA.
You should create a Child Form only Once .
ChildFormA form1 = new ChildFormA();
if(form1 == null)
{
form1.MdiParent = this;
form1.Show();
}
else
form1.Show();
than you should use Matthias Koch solution ,on child Forms
void FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
Also Keep ChilFormA as a MDI Class Field ,so you won't lose Ref. to it.
to prevent the form from closing is described here. I would also advice hide, but maybe it works to set visible to false...
You could use the Singleton pattern in for this Form.
http://csharpindepth.com/Articles/General/Singleton.aspx
Look at the 4th approach
Then you would access it using the static instance instead of creating a new one.
You still need Matthias Koch solution ,on child Forms
void FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
If you need further help with the Singleton pattern, please say so.

C# Why does form.Close() not close the form?

I have a button click event handler with the following pseudo code:
private void btnSave_Click(object sender, EventArgs e)
{
if(txt.Text.length == 0)
this.Close();
else
// Do something else
// Some other code...
}
This is just some simple code, but the point is, when the text length equals zero, I want to close the form. But instead of closing the form the code executes the part // Some other code. After the click event handler is completely executed, then the form is closed.
I know, when I place return right after this.Close() the form will close, but I'd like to know WHY the form isn't direclty closed when you call this.Close(). Why is the rest of the event handler executed?
The rest of the event handler is executed because you did not leave the method. It is as simple as that.
Calling this.Close() does not immediately "delete" the form (and the current event handler). The form will be collected later on by the garbage collector if there are no more references to the form.
this.Close() is nothing than a regular method call, and unless the method throws an exception you will stay in the context of your current method.
Close only hides the form; the form is still alive and won't receive another Load event if you show it again.
To actually delete it from memory, use Dispose().
Answer is simple as you are executing your current method so this.Close() will be enqueued until either you explicitly returned or your current excuting method throws an exception.
Another possible solution is that if you open a new Form and want to close the current one: if you use newForm.ShowDialog() instead of newForm.Show() it doesn't close the currentForm with currentForm.Close() until the newForm is also closed.
Unless the Form is a modal form(opened with .ShowDialog()), Form.Close() disposes the form, as well. So, you cannot reopen it under any circumstances after that, despite of what others may have said. There is Form.Visible for this behavior(hiding/showing the form).
The point here is that .Close() does not return from the section it is called for several reasons. For example, you may call SomeForm.Close() from another form or a class or whatever.
Close() is just a method like any other. You have to explicitly return from a method that calls Close() if this is what you want.
Calling MessageBox.Show(frmMain,"a message","a title") adds the form "TextDialog" to the application's Application.OpenForms() forms collection, along-side the frmMain Main form itself. It remains after you close the Messagebox.
When this happens and you call the OK button delegate to close the main form, calling frmMain.Close() will not work, the main form will not disappear and the program will not terminate as it usually will after you exit the OK delegate. Only Application.Exit() will close all of the garbage messagebox "TextDialog"s.
private void btnCloseForm_Click(object sender, EventArgs e)
{
FirstFrm.ActiveForm.Close();
}
and if you want close first form and open secound form do this :
private void btnCloseForm_Click(object sender, EventArgs e)
{
FirstFrm.ActiveForm.Close();
}
private void FirstFrm_FormClosed(object sender, FormClosedEventArgs e)
{
SecounfFrm frm = new SecounfFrm ();
frm.ShowDialog();
}
or you can do somting like that :
private void btnCloseForm_Click(object sender, EventArgs e)
{
this.Hide();
}
private void FirstFrm_VisibleChanged(object sender, EventArgs e)
{
if(this.Visible == false)
{
this.Close();
}
}
private void FirstFrm_FormClosed(object sender, FormClosedEventArgs e)
{
SecounfFrm frm = new SecounfFrm ();
frm.ShowDialog();
}

C# Windows Form: On Close Do [Process]

How can I get my windows form to do something when it is closed.
Handle the FormClosed event.
To do that, go to the Events tab in the Properties window and double-click the FormClosed event to add a handler for it.
You can then put your code in the generated MyForm_FormClosed handler.
You can also so this by overriding the OnFormClosed method; to do that, type override onformcl in the code window and OnFormClosed from IntelliSense.
If you want to be able to prevent the form from closing, handle the FormClosing event instead, and set e.Cancel to true.
Or another alternative is to override the OnFormClosed() or OnFormClosing() methods from System.Windows.Forms.Form.
Whether you should use this method depends on the context of the problem, and is more usable when the form will be sub classed several times and they all need to perform the same code.
Events are more useful for one or two instances if you're doing the same thing.
public class FormClass : Form
{
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
// Code
}
}
WinForms has two events that you may want to look at.
The first, the FormClosing event, happens before the form is actually closed. In this event, you can still access any controls and variables in the form's class. You can also cancel the form close by setting e.Cancel = true; (where e is a System.Windows.Forms.FormClosingEventArgs sent as the second argument to FormClosing).
The second, the FormClosed event, happens after the form is closed. At this point, you can't access any controls that the form had, although you can still do cleanup on variables (such as Closing managed resources).
Add an Event Handler to the FormClosed event for your Form.
public class Form1
{
public Form1()
{
this.FormClosed += MyClosedHandler;
}
protected void MyClosedHandler(object sender, EventArgs e)
{
// Handle the Event here.
}
}
public FormName()
{
InitializeComponent();
this.FormClosed += FormName_FormClosed;
}
private void FormName_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
{
   //close logic here
}
Syntax :
form_name.ActiveForm.Close();
Example:
{
Form1.ActiveForm.close();
}

Categories