C# 无法访问已释放的对象

C# 无法访问已释放的对象,c#,.net,vb.net,winforms,dispose,C#,.net,Vb.net,Winforms,Dispose,我面临着一个巨大的问题,“无法访问已处理的对象。对象名称:'TreeView'”错误 在我的windows窗体上,我使用了一个 下面是代码部分 在selected node事件中,我将在所选目录中找到的图像加载到FlowLayoutPanel Private Sub ExpTree1_ExpTreeNodeSelected(ByVal SelPath As String, ByVal Item As ExplorerControls.CShItem) Handles ExpTree1.ExpT

我面临着一个巨大的问题,
“无法访问已处理的对象。对象名称:'TreeView'”
错误

在我的windows窗体上,我使用了一个

下面是代码部分

在selected node事件中,我将在所选目录中找到的图像加载到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
sub中的代码继续执行。将所有图像加载到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
,然后确认应用程序关闭,则不会出现错误。

基本上,当您对已处置的仍然处于活动状态的对象执行操作时,会发生这种情况。所以要么像这样:

A a = new A();
a.Dispose();
//operations performed on a will fail now
还是像这样

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

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

这里发生的事情是启动一个线程来处理TreeView对象,然后在线程完成之前,TreeView被处理掉


要解决此问题,请检查TreeView是否可用于操作,或者是否未在线程中使用TreeView的
IsDisposed
属性进行处理。

您应该将
加载图像的相关部分发布到FlowPreviewPanel
方法

这是没有看到代码的推测,但一种解释可能是:

  • LoadImagesToFlowPreviewPanel正在循环中调用
    应用程序.DoEvents

  • 在调用
    Application.DoEvents

  • 但是循环继续执行并访问已处理的树视图

如果是这样,解决方案可能是重新设计以避免调用
Application.DoEvents
,或者至少检查表单是否关闭/TreeView是否在每次调用
Application.DoEvents
后被释放

更新回应评论:


哇!实际上,LoadImages正在循环中调用Application.DoEvents


如果使用
Application.DoEvents
会使自己暴露在代码中的重入问题中-您需要非常小心,并确保在使用它时理解所有后果。你所描述的问题并不是你可能面临的唯一问题。我只会在非常特殊的情况下使用它,我可以保证不会出现重入问题(例如,当显示模式进度对话框时)。许多人会称DoEvents为“邪恶”,而与之毫无关系。

LoadImagesToFlowPreviewPanel()方法发生了什么事?除非您在单独的线程上运行该方法,否则除非该方法完成运行,否则您将无法关闭表单。你的“循环直到所有图像加载”是什么意思?我没有看到一个环…哇!实际上LoadImages正在调用
应用程序。DoEvents
在一个循环中我不同意
DoEvents
是“邪恶的”,但这是一种严重的代码气味。这可能导致难以诊断bug(如本例),并且表明对Windows事件驱动模型的理解不足。唯一应该使用它的人是那些对它所做的事情有着透彻理解和欣赏的人,他们通常是那些找到更好的方法使代码工作的人。他说,你的答案是正确的;我不知道为什么到目前为止我是唯一一个投票支持它的人,为什么它没有被接受。你的心理调试器比我的调试器校准得好得多。@Cody-我完全同意你的看法。至于向上投票,我的经验是,普通问题的答案比像这样的具体问题更吸引他们。但我的积分比我能花的还多,所以我不担心:)