ObjectDisposedException

G

gol

Hi,
I have an invisible button in my form. I have a timer
(System.Windows.Forms.Timer) with interval 300 ms. In the timer tick event I
check for a certain flag, and if that flag is true, the button becomes
visible (After setting the flag's status to false again).

The problem is that if the event happened and the button became visible, and
then I closed the form, and then reopened it and let the event happen again,
then the operation of making the button visible throws an exception of type
System.ObjectDisposedException.

It looks like when I reopen the form, I already haven't got the button. One
could think it's been Garbage Collected, but I'm not sure about that, because
the button is part of the form which is reopened (Form f = new Form(); ).

Can someone please explain the source of the problem and the solution?
Thanks a lot
 
M

Morten Wennevik [C# MVP]

Hi,

I'm guessing the timer event is for the "old" timer and the code tries to
make the "old" button visible, which probably has been garbage collected.
Make sure you stop the timer when you close the form, and in your event code
check

if(button1.IsDisposed || button1.Disposing)
return;
 
C

cody

gol said:
Hi,
I have an invisible button in my form. I have a timer
(System.Windows.Forms.Timer) with interval 300 ms. In the timer tick event I
check for a certain flag, and if that flag is true, the button becomes
visible (After setting the flag's status to false again).

The problem is that if the event happened and the button became visible, and
then I closed the form, and then reopened it and let the event happen again,
then the operation of making the button visible throws an exception of type
System.ObjectDisposedException.

It looks like when I reopen the form, I already haven't got the button. One
could think it's been Garbage Collected, but I'm not sure about that, because
the button is part of the form which is reopened (Form f = new Form(); ).

Can someone please explain the source of the problem and the solution?
Thanks a lot

You must Stop() & Dispose() the timer before closing the form.
Otherwise, the timer still runs although the Form is already disposed.
 
G

gol

Thank you all very much for your answers,
I'll try to explain my problem in more details. The way I see it, the timer
is not the problem, and actually I don't need the timer.

I am receiving an event in a delegate. The event is received correctly, on
time, exactly as expected. As soon as receiving the event I want to make the
button visible. This didn't succeed so I thought of using a flag and a timer
(because I remember once using that method worked well for me). This didn't
solve the problem.
The basic problem remained the same: When reopening the form, and receiving
the event, the button is already disposed. I tried to change the button's
visibility in the constructor and there it succeeds also in the second time.
(There is no exception).

I thought about it a lot, and there is something that I want to ask if this
may cause this problem. In the class where I receive the event I also have an
instance of the class that fires the event. However, it's defined as static.
So I think that on the second time of event firing, it's still the first
firing class trying to fire the event to the second receiving class, in which
it is not defined. Is this true?
Is there a way to keep that instance static and make the other things work
correctly?

What bothers me regarding this is that I use the same event receiving
mechanism for a different event and it works perfect. And another thing that
I don't understand- suppose I am using the timer, after entering the
timer_tick event handler the button should be the one that belongs to the
instance of the class that is now running, regardless of the event firing
class. Is this true?

I forgot to mention that I work in .Net Compact Framework 2.0.

Thank you all very much
 
G

gol

Hi,
This is my code:

namespace MyAPP
{
public delegate void MyDelegateDel(object sender, MyEventArgs e);

public partial class A : Form
{
public static B b;

private static MyDelegateDel DataHandler;

public A()
{
if (DataHandler == null)
{
DataHandler = new MyDelegateDel(Data_Event);
}

if (b == null)
{
b = new B();
b.ReceivedEvent += DataHandler;
}
}

public void Data_Event(object sender, MyEventArgs e)
{
if (e.MyParam == 20)
Button1.Visible = true;
}
}

public class B
{
public event MyDelegateDel ReceivedEvent;

public B()
{
}

private void SomeMethod()
{
MyEventArgs e = new MyEventArgs();
e.MyParam = 10;
ReceivedEvent(this, e);
}

private void AnotherMethod()
{
MyEventArgs e = new MyEventArgs();
e.MyParam = 20;
ReceivedEvent(this, e);
}

}
}

Thank you very much for your help

Patrice said:
The way I see it, the timer
is not the problem, and actually I don't need the timer.

Copy your project and get rid of all that is not related to the problem...
When reopening the form, and receiving
the event, the button is already disposed.

So the button reference you have seems to belong to the previous from
instance. Not to the current form instance. Have you tried to stop there and
check whihc instance you are using. For example you could initialize a
random label
[Code description]

IMO a description will never replace the actual code so that there were are
crystal clear about what your code does. Usually it's best to :
1) simplify your code to the maximum so that you can concentrate on the
problem at hand. During this process you'll likely find & fix the problem
2)if not fixed, you can then post your simple repro code so that we can see
what you are doing and why it fails

It's crucial to NOT cut/paste your current code that likely contains details
that are irrelevant to the problem (making most people unwilling to browse
through the whole code to pick the relevant lines) but to post the smallest
amount of working code that shows the problem...
 
G

gol

Thank you very much,
Is there a way I can leave
this line as is:
public static B b;
Thanks

Patrice said:
Just suppress the "static" keyword before both members and it should
work....

A delegate is basically a function pointer. It won't automatically point to
a new instance by using the name of the function (it looks like you expect
it dynamically binds to the function for the current instance ?). When
stored you just store a pointer to a function that is resolved once for all
and it will be kept unchanged unless you are telling otherwise so here
you'll point to the function that belongs to the first instance and only
this one. So when disposed and using a new instance, it is unchanged and
still try to work with the first instance...



--
Patrice


gol said:
Hi,
This is my code:

namespace MyAPP
{
public delegate void MyDelegateDel(object sender, MyEventArgs e);

public partial class A : Form
{
public static B b;

private static MyDelegateDel DataHandler;

public A()
{
if (DataHandler == null)
{
DataHandler = new MyDelegateDel(Data_Event);
}

if (b == null)
{
b = new B();
b.ReceivedEvent += DataHandler;
}
}

public void Data_Event(object sender, MyEventArgs e)
{
if (e.MyParam == 20)
Button1.Visible = true;
}
}

public class B
{
public event MyDelegateDel ReceivedEvent;

public B()
{
}

private void SomeMethod()
{
MyEventArgs e = new MyEventArgs();
e.MyParam = 10;
ReceivedEvent(this, e);
}

private void AnotherMethod()
{
MyEventArgs e = new MyEventArgs();
e.MyParam = 20;
ReceivedEvent(this, e);
}

}
}

Thank you very much for your help

Patrice said:
The way I see it, the timer
is not the problem, and actually I don't need the timer.

Copy your project and get rid of all that is not related to the
problem...

When reopening the form, and receiving
the event, the button is already disposed.

So the button reference you have seems to belong to the previous from
instance. Not to the current form instance. Have you tried to stop there
and
check whihc instance you are using. For example you could initialize a
random label

[Code description]

IMO a description will never replace the actual code so that there were
are
crystal clear about what your code does. Usually it's best to :
1) simplify your code to the maximum so that you can concentrate on the
problem at hand. During this process you'll likely find & fix the problem
2)if not fixed, you can then post your simple repro code so that we can
see
what you are doing and why it fails

It's crucial to NOT cut/paste your current code that likely contains
details
that are irrelevant to the problem (making most people unwilling to
browse
through the whole code to pick the relevant lines) but to post the
smallest
amount of working code that shows the problem...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top