"Cannot access a disposed object" - weird exception.

R

Ryan Park

Hi,

//SITUATION
I got a panel control that hold a certain position on a form.
Every controls or UIs are on this panel.

At certain situation, I called dispose() method of this panel control
and change it with other panel which contains other business logic and
UI controls.

//ACTUAL CODE PRAGMENT & SYMPTOMS
//_body is a member panel control on the form control.
//And on this panel there is another panel control that holds other UI
controls.

if(_body.Controls.Count > 0)
{
_body.Controls[0].Dispose(); //always ther is only 1 child.
_body.Controls.Clear();
}
_body.Controls.Add(control);
Application.DoEvents();

This works well. But after some time ( a few seconds maybe), I got
"System.ObjectDisposedException: Cannot access a disposed object named
\"LoginForm\".

LoginForm is a control type. It's not a name of control.
And this LoginForm is on the _body.Controls[0] panel.
And LoginForm.Dispose() get called when _body.Controls[0].Dispose();
line executes.

//MY QUESTION
I have no idea how this happen. Since I call dispose(), I think there
should be no reference to panel instance.

I've tried GC.SuppressFinalize(), but not works either.

How can I fix this code? Or Is this a bug of .NET?

Any suggestion would be appreciated. TIA. :)

Regards,
Ryan


//POST SCRIPT - WHOLE ERROR MESSAGE
"System.ObjectDisposedException: Cannot access a disposed object named
\"LoginForm\".\r\nObject name: \"LoginForm\".\r\n at
System.Windows.Forms.Control.CreateHandle()\r\n at
System.Windows.Forms.Control.get_Handle()\r\n at
System.Windows.Forms.ContainerControl.FocusActiveControlInternal()\r\n
at System.Windows.Forms.Form.set_Active(Boolean value)\r\n at
System.Windows.Forms.Form.WmActivate(Message& m)\r\n at
System.Windows.Forms.Form.WndProc(Message& m)\r\n at
System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)\r\n
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)\r\n
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)\r\n at
System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg,
HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)\r\n at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)\r\n at
System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)\r\n at
System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)\r\n at
System.Windows.Forms.Application.Run(Form mainForm)\r\n at
WindowsApplication1.Form1.Main() in
c:\\src\\smart\\windowsapplication1\\form1.cs:line 88"
 
N

news.saix.net

Dispose does not remove all the references at all, it is up to you to ensure
this happens. Dispose is used to clean up an objects resources, so that they
are not held open whilst awaiting a garbage collection. That's all. So
basically, you appear to have a reference somewhere to the disposed panel,
and your code is attempting to access it and use it. Said code appears to be
attempting an operation on the panel that requires the resources you've just
disposed to be available.

Dispose - Used to manually clear up resources when object is no longer
needed.
Finalize - Used to automatically clear up resources when object is garbage
collected.

The object will only be destroyed some arbitrary time after all references
to it are cleared.

From your stack trace, it looks like set_Active is trying to set focus to
the disposed panel.

HTH

http://codingsanity.blogspot.com

Ryan Park said:
Hi,

//SITUATION
I got a panel control that hold a certain position on a form.
Every controls or UIs are on this panel.

At certain situation, I called dispose() method of this panel control
and change it with other panel which contains other business logic and
UI controls.

//ACTUAL CODE PRAGMENT & SYMPTOMS
//_body is a member panel control on the form control.
//And on this panel there is another panel control that holds other UI
controls.

if(_body.Controls.Count > 0)
{
_body.Controls[0].Dispose(); //always ther is only 1 child.
_body.Controls.Clear();
}
_body.Controls.Add(control);
Application.DoEvents();

This works well. But after some time ( a few seconds maybe), I got
"System.ObjectDisposedException: Cannot access a disposed object named
\"LoginForm\".

LoginForm is a control type. It's not a name of control.
And this LoginForm is on the _body.Controls[0] panel.
And LoginForm.Dispose() get called when _body.Controls[0].Dispose();
line executes.

//MY QUESTION
I have no idea how this happen. Since I call dispose(), I think there
should be no reference to panel instance.

I've tried GC.SuppressFinalize(), but not works either.

How can I fix this code? Or Is this a bug of .NET?

Any suggestion would be appreciated. TIA. :)

Regards,
Ryan


//POST SCRIPT - WHOLE ERROR MESSAGE
"System.ObjectDisposedException: Cannot access a disposed object named
\"LoginForm\".\r\nObject name: \"LoginForm\".\r\n at
System.Windows.Forms.Control.CreateHandle()\r\n at
System.Windows.Forms.Control.get_Handle()\r\n at
System.Windows.Forms.ContainerControl.FocusActiveControlInternal()\r\n
at System.Windows.Forms.Form.set_Active(Boolean value)\r\n at
System.Windows.Forms.Form.WmActivate(Message& m)\r\n at
System.Windows.Forms.Form.WndProc(Message& m)\r\n at
System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)\r\n
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)\r\n
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)\r\n at
System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg,
HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)\r\n at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)\r\n at
System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)\r\n at
System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)\r\n at
System.Windows.Forms.Application.Run(Form mainForm)\r\n at
WindowsApplication1.Form1.Main() in
c:\\src\\smart\\windowsapplication1\\form1.cs:line 88"
 
R

Ryan Park

Hi, thanks for your resply.

My points are :

#1 Finalize() is protected member. So it's not callable by user.

#2 Attached call stack code (like set_Active) is not my code. It's CLR
execution code. I'm sure there is no reference to disposed object after
dispose() call. Since this is called by CLR, I have no idea how to fix
this problem.

#3 I want to optimize memory usage, so how can I clear up the object in
memory when I want to safely?

Again TIA

- Ryan
 
J

Joakim Karlsson

Ryan said:
#1 Finalize() is protected member. So it's not callable by user.

Correct, the finalizer is called by a dedicated finalizer thread after
an object has been collected.
#2 Attached call stack code (like set_Active) is not my code. It's CLR
execution code. I'm sure there is no reference to disposed object after
dispose() call. Since this is called by CLR, I have no idea how to fix
this problem.

Could it be that you are disposing a control that has focus? Try setting
focus to one of the controls not being removed from the form.
#3 I want to optimize memory usage, so how can I clear up the object in
memory when I want to safely?

What are you trying to optimize? The GC is generally pretty good at this
.. Unless you are wrapping an unmanaged resource such as a file or a
database connection that you need to release as quickly as possible, let
the GC just do its job.

I think what you are experiencing is a good example of how interfering
with the GC may lead to complications.

/Joakim
 
R

Ryan Park

Hi, jaokim. Thanks for you reply.
Could it be that you are disposing a control that has focus? Try setting
focus to one of the controls not being removed from the form.

I think this opinion is highly considerable. I'll check this out.
What are you trying to optimize?

My custom child is very heavy. And other business forms are also heavy.

So I don't want to wait the GC's unpredictable garabage collection
activity.
I want the control (or form) to be unloaded ASAP it ends up its
functionality.

The GC is generally pretty good at this
. Unless you are wrapping an unmanaged resource such as a file or a
database connection that you need to release as quickly as possible, let
the GC just do its job.

I thought exatly the same as you..GC is very dependable on memory
management. But there is a memory problem if I don't erase the object
manually. On every new business form loaded, the previous object is not
unloaded from memory until it is not exclusively to do so. I found this
thru monitoring the memory usage. Since the panel area embedding a
every new business forms (or controls), it should be cleared properly
at every new business sequence.

I thoght I have done this job throught Controls.Clear() but it is not.
Obviously, there is no reference about the objects, but it is not
cleared properly.

Till now, I didn't find any proper memory management method but
dispose().

So....I think maybe I'm not good enough to deal with this problem..

Any suggestion?? TIA.

-Ryan
 
M

Mujtaba Syed

My custom child is very heavy. And other business forms are also heavy.
So I don't want to wait the GC's unpredictable garabage collection
activity.
I want the control (or form) to be unloaded ASAP it ends up its
functionality.

This would be a good (and only one of a few) place to call System.GC.Collect
().
Make sure that you have released all references to you control before doing
so.

Check out this post from Rico Mariani:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx

Mujtaba.
 
M

Matt Garven

I think what you are experiencing is a good example of how interfering
with the GC may lead to complications.

When a control is removed from a control collection, never to be used again,
the correct behaviour is to dispose it - if a control has no parent then it
has nothing to dispose it so it needs to be done manually. I don't see the
point of letting it sit on the finalization queue.

Regards,
Matt
 
R

Ryan Park

Hi, sorry for late posting

My problem was solved by removing the focus from control before dispose
it. I guess window object of Windows OS is not tightly coupled with
Control object in .NET.

Though solvd the problem, I'm not satisfied with this feature of .NET.
I thinks it should erase proper window handle when I call
Controls.Clear().

And thank jaokim for your advice. :)
Hope this posting help others like me.

Regards,
Ryan
 

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