How to Dispose a New Form

Proper way to dispose a new Form

Hmm, "code cracker" appears to be a very appropriate term for that tool, its advice certainly made you write code that breaks your program. Golden Rule is to never trust IDisposable advice from a static code analysis tool, none of them ever have sufficient insight in code execution. They can never figure out which Dispose() call gets the job done.

What it cannot see is that the Form class already knows how to dispose itself. It is very easy for it to do so, the object becomes unusable when the window closes. When there is no more window then there's no reason to keep using the Form object. A luxury that isn't otherwise very common in .NET but certainly inspired by very smart programmers that worked for Xerox 45 years ago.

There is only one special rule you have to keep in mind, it does not dispose itself when you use ShowDialog() to display the window. That was intentional, it makes retrieving the dialog results too risky. Using the using statement for a ShowDialog() call is very easy to do, the call does not return until the window is closed.

C# Form.Close vs Form.Dispose

This forum on MSDN tells you.

Form.Close() sends the proper Windows
messages to shut down the win32
window. During that process, if the
form was not shown modally, Dispose is
called on the form. Disposing the form
frees up the unmanaged resources that
the form is holding onto.

If you do a form1.Show() or
Application.Run(new Form1()), Dispose
will be called when Close() is called.

However, if you do form1.ShowDialog()
to show the form modally, the form
will not be disposed, and you'll need
to call form1.Dispose() yourself. I
believe this is the only time you
should worry about disposing the form
yourself.

Disposing a form from parent form in C#?

If the two forms doesn't have a parent-dialog type of relationship, you might just want to hook into the Disposed event on the subform to get notified when it closes.

public partial class Form1 : Form
{
private Form2 _Form2;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
if (_Form2 != null)
_Form2.Dispose();

_Form2 = new Form2();
_Form2.Disposed += delegate
{
_Form2.Dispose();
_Form2 = null;
};
_Form2.Show();
}
}

Then all you have to do in Form2 is simply to close it:

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

private void button1_Click(object sender, EventArgs e)
{
Close();
}
}

Totally form Disposing and free up memory

I'm not really familiar with VB, but I think it will do things similar as to how they are done using winforms for C#

The easiest way to make sure that all Disposable objects of A Form are disposed when the form is disposed, to keep a collection of Disposable objects. You could use the existing class Sytem.ComponentModel.Component class for this. The disadvantage is that it only accepts objects that implement interface IComponent. If you have only a few classes that must be disposed that don't have this interface yet, this is the easiest method. Otherwise design your own DisposableCollection

class DisposableCollection : List<object>, IDisposable
{
public bool IsDisposed {get, private set} = false;

private IEnumerable<IDisposable> DisposableItems => this.OfType<IDisposable>();

public void Dispose()
{
if (!this.IsDisposed)
{
// Dispose all disposable items
foreach (IDisposable disposableItem in this.DisposableItems)
{
disposableItem.Dispose();
}
this.disposed = true;
}
}
}

Usage:

class MyForm : Form
{
private readonly DisposableCollection disposables = new DisposableCollection();

public MyForm()
{
// create and add all your items to disposables
}

protected override void OnDisposing(bool disposing)
{
this.disposables.Dispose();
}
}

If desired you can add event handlers to notify others that the object is being disposed

Does a Windows.Form need to be disposed after being closed?

The general rule is anything which implements IDisposable should be disposed. This includes forms, since the base Form is IDisposable. Furthermore, steps should be taken to ensure disposal even in the event of an exception. Therefore, the better pattern typically looks like this:

if (sth_goes_wrong) {
using (var formWarn = new FormWarn("explanatory message..."));
{
formWarn.ShowDialog();
}
}

Note I did not use the member variable and showed the form using a blocking dialog.

Alternatively, you can continue using the member variable. However, in that case you need to override the current form's Dispose() method to also dispose your formWarn instance, if it exists, and the code in question should look like this:

if (sth_goes_wrong) {
this.formWarn = this.formWarn ?? new FormWarn();
formWarn.Message = "explanatory message...";
formWarn.Show();
}

where you also added that new Message property allowing you to update an existing instance.

How to correctly dispose a Form, without risk of an Invoke being called from another thread on a disposed object?

There are two approaches to consider. One is to have a locking object within the Form, and have the internal calls to Dispose and BeginInvoke calls occur within the lock; since neither Dispose nor BeginInvoke should take very long, code should never have to wait long for the lock.

The other approach is to just declare that because of design mistakes in Control.BeginInvoke/Form.BeginInvoke, those methods will sometimes throw an exception that cannot practically be prevented and should simply be swallowed in cases where it won't really matter whether or not the action occurs on a form which has been disposed anyway.

Dispose form after closing

This question turns out to be about Dispose.

Firstly, Dispose has nothing 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;


Related Topics



Leave a reply



Submit