views:

91

answers:

4

Dear friends

I have got the new problem with opening and closing form in C#.

My problem is how to dispose the form after closing .

here is my code :

Program.cs:

static class Program
{
    public static Timer timer;

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        timer = new Timer { Interval = 1000};
        timer.Start();

        Application.Run(new Form1());
    }
}

Form1.cs:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 form = new Form2();
        form.ShowDialog();
       /// I've tried Dispose() method . but didn't work
    }
}

Form2.cs:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {
        Program.timer.Tick += timer_Tick;    
        Close();
        // I've tried Dispose() method instead of Close() but didn't work
    }

    private int count = 0; 
    void timer_Tick(object sender, EventArgs e)
    {
        count++;
        if (count == 5) MessageBox.Show("");
    }
}

Edited : My question is : why the message box shows after 5 seconds when the form2 has closed!

A.mz

+4  A: 

Edit: This question turns out to be about Dispose.

Firstly, Dispose has noting to do with garbage collection. The following happens:

  1. You have a global Timer instance
  2. You create form2
  3. Form2 subscribes to the timer
  4. Form2 is Closed and/or Disposed
  5. The Timer event fires, increments the counter and shows a MessageBox
  6. The Timer event keeps firing until the App closes.

The main point to understand is that Close/Dispose only change the status of the Form, they don't (can't) 'delete' the instance. So the (closed) form is there, the counter field is still there and the Event fires.


OK, part 1:

A using () {} block would be better but this should work:

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 form = new Form2();
        form.ShowDialog();
       /// I've tried Dispose() method . but didn't work
        form.Dispose(); // should work
    }

If not, please describe "doesn't work".


    private void Form2_Load(object sender, EventArgs e)
    {
        Program.timer.Tick += timer_Tick;    
        Close();
       /// I've tried Dispose() method instead of Close() . but didn't work
    }

This is strange, but I'll assume that it is artifical code for the question.

Your global Program.Timer now stores a reference to your Form2 instance and will keep it from being collected. It does not prevent it from being Disposed/Close so your timer will keep firing for a Closed Form, and that will usually fail and cause other problems.

  1. Don't do this (give Form2 it's own timer)
  2. Use a FormClosed event to unsubscribe: Program.timer.Tick -= timer_Tick;
Henk Holterman
+1 For suggesting using statement, might want to give him an example.
jsmith
Dear Henk Holterman , removing the timer tick event is the good solution , But my question is , Why the message box shows when the form has disposed ?
Mironline
@Mironline: Why shouldn't it? Neither the Timer nor the MessageBox need that form. Try to set a Control property in timer_Tick and you will have an exception.
Henk Holterman
A: 

The simplest and most reliable way to dispose a Form after using is to put the usage inside of a using block

using (Form2 form = new Form2()) {
  form.ShowDialog();
}

The using block in C# is a construct that essentially expands the above into the following code.

Form2 form;
try {
  form = new Form2(); 
  ...
} finally {
  if ( form != null ) {
    form.Dispose();
  }
}
JaredPar
in seconds block , form2 have to initialize before accessing. and if it initialized never equals to null. I've tried that but the message box shows after 5 sec.
Mironline
A: 

form.ShowDialog() shows the form as a modal dialog. This means that the call doesn't return until the Form is closed.
Note that clicking the close X on a modal dialog doesn't close the form, it just hides it. I am guessing that this is what confuses you. If you want the code in form1 to continue executing rather than blocking, you should call Show() instead of ShowDialog(). Non-modal will close when the X is clicked.

If you do want a blocking modal dialog, you should surround the form with a using block as described in the other answers.
When building a modal dialog you would typically add an "OK" button or similar and set the AcceptButton property of the form to that button to allow the user to close the form by pressing enter. Similarly you can add a "Cancel" button and set the CancelButton property to capture the Esc key.
Add a click handler to the two buttons, set the DialogResult property of the form accordingly and call Close().

Holstebroe
A: 

If I understand you correctly, you are asking why the message box still shows even after you closed the form before the timer fired.

This is because the timer event still has a reference to your instance of Form2. Disposing of something doesn't force garbage collection, it just calls whatever code is in the Dispose() method. Your form still exists until there are no more references to it.

For this to work the way you want, you need to disable the timer or remove the event handler when the form closes.

protected override void OnFormClosed(FormClosedEventArgs e)
{
    base.OnFormClosed(e);

    timer.Stop();

    // or

    Program.timer.Tick -= timer_Tick;    
}
Jon B