无法访问已释放的对象。

5

我遇到了一个巨大的问题,错误信息为"Cannot access a disposed object. Object name: 'TreeView'"

在我的Windows窗体上,我使用了自定义Windows资源管理器对象

以下是相关代码...

当选择节点事件发生时,我将选定目录中找到的图像加载到FlowLayoutPanel中。

 Private Sub ExpTree1_ExpTreeNodeSelected(ByVal SelPath As String, ByVal Item As ExplorerControls.CShItem) Handles ExpTree1.ExpTreeNodeSelected
      'Loop until all images are loaded.
       LoadImagesToFlowPreviewPanel()
 End Sub

在关闭按钮事件中。
 Private Sub WizardControl1_CancelClick(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles WizardControl1.CancelClick
        Me.Close()
 End Sub

在窗体关闭事件中。
 Private Sub Wizard_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
                Select Case XtraMessageBox.Show("Exit the application?", Me.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                Case Windows.Forms.DialogResult.No
                    e.Cancel = True
                End Select
        End If
 End Sub

在调试时,我注意到当我确认关闭应用程序时,LoadImagesToFlowPreviewPanel子程序中的代码仍然会继续执行。当所有图像加载到FlowLayoutPanel控件时,就会引发错误。
以下是堆栈跟踪...
   at System.Windows.Forms.Control.CreateHandle()
   at System.Windows.Forms.TreeView.CreateHandle()
   at System.Windows.Forms.Control.get_Handle()
   at System.Windows.Forms.TreeView.TvnSelected(NMTREEVIEW* nmtv)
   at System.Windows.Forms.TreeView.WmNotify(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
   at System.Windows.Forms.Control.WmNotify(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Application.ParkingWindow.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
   at System.Windows.Forms.TreeView.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
   at CannonUpdater.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 82
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

更新: 如果所有的图像都加载到 FlowLayoutPanel 中,并且应用程序关闭的确认接下来出现,我就不会出现错误。


LoadImagesToFlowPreviewPanel() 方法发生了什么?除非您在单独的线程上运行它,否则在该方法完成运行之前,您将无法关闭窗体。您的“循环直到所有图像加载完毕”注释是什么意思?我没有看到循环... - Cody Gray
3个回答

4

基本上,当您对一个仍然存在但已被处理的对象执行操作时,就会发生这种情况。所以要么像这样:

A a = new A();
a.Dispose();
//operations performed on a will fail now

Or like this

using( A a = new A()){
  ...
}
//operations performed on a will fail now

请记住,使用using块也会像手动调用Dispose一样处理您的对象。


4
您应该发布LoadImagesToFlowPreviewPanel方法中相关的部分。
这只是猜测,没有看到代码,但一个解释可能是:
- LoadImagesToFlowPreviewPanel在循环中调用了Application.DoEvents - 窗体在调用Application.DoEvents期间关闭,并且TreeView在其中一个调用期间被处理 - 但是循环继续执行并访问已处理的TreeView
如果是这样,解决方案要么重新设计以避免调用Application.DoEvents,要么至少在每次调用Application.DoEvents后检查窗体是否关闭/TreeView是否已经处理。
更新回复评论:
哇!实际上,LoadImages在循环中调用Application.DoEvents。
如果使用Application.DoEvents,则会在代码中暴露自己的可重入性问题 - 您需要非常小心,并确保在使用它时了解所有后果。您描述的问题不是您可能面临的唯一问题。我只会在非常特定的情况下使用它,在这些情况下我可以保证不会出现可重入性问题(例如,显示模式进度对话框时)。许多人会称呼DoEvents为“邪恶”,并根本不使用它。

哇!实际上,LoadImages 在循环中调用了 Application.DoEvents - GeorgeBoy
1
我不同意DoEvents是“邪恶”的说法,但它确实是一种严重的代码异味。它可能导致难以诊断的错误(比如这个),并且表明了对Windows事件驱动模型的理解不足。唯有那些彻底理解并欣赏它所做工作的人才应该使用它,通常这些人会找到更好的方法使其代码工作。话虽如此,你的回答是正确的;我不知道为什么只有我点赞了它,并且为什么它还没有被接受。你的预知调试器比我的要准确得多。 - Cody Gray
@Cody - 我完全同意你的观点。至于赞同,我的经验是针对普遍问题的答案比这种具体问题更容易吸引它们。但我有比我能用掉的更多积分,所以我不担心 :) - Joe

0
这里发生的情况是您启动了一个线程来操作TreeView对象,然后在线程完成之前,TreeView被处理掉了。
为了解决这个问题,在您的线程中检查TreeView是否可用于操作或未被处理,可以使用TreeView的IsDisposed属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接