使用Gif关闭窗体会抛出InvalidOperationException

时间:2014-12-22 19:20:26

标签: vb.net multithreading user-interface datagridview

这显然是我无法理解如何正确设置UI线程的问题,但我无法弄清楚如何解决它。

我有一个datagridview,我单击一个按钮,从网络获取信息,然后使用新数据在datagridview上显示它。虽然它在网络上,我有一个表格,我用一个更新的gif,一个我称为“加载”的表单。在该表单中,我使用互联网上的典型OnFrameChanged和m_isAnimating代码进行gif更新。

但是,无论我使用何种格式,我总是会在此处捕获此异常:

    Public loader As New Loading
    Private Sub OnFrameChanged(ByVal o As Object, ByVal e As EventArgs)

    Try  ' If animation is allowed call the ImageAnimator UpdateFrames method
        ' to show the next frame in the animation.
        Me.Invalidate()
        If m_IsAnimating Then
            ImageAnimator.UpdateFrames()
            Me.Refresh()
            'Draw the next frame in the animation.
            Dim aGraphics As Graphics = PictureBox1.CreateGraphics
             aGraphics.DrawImage(_AnimatedGif, New Point(0, 0))
                            aGraphics.Dispose()
        End If
    Catch ex As InvalidOperationException

    End Try
End Sub

它通常会说“从未创建的线程访问”或“无法访问已处置的对象。对象名称:'PictureBox'。”

但我不知道为什么会这样,因为我每次都在这里创建一个新实例。这是按钮的代码:

 Private Sub btnSlowSearch_Click(sender As Object, e As EventArgs) Handles btnSlowSearch.Click

        Me.Cursor = Cursors.WaitCursor

        'get datatable

        loader.Show()
        BWorkerLoadProp.RunWorkerAsync() 'go get data on network 
        'bworker will update datagridview with new data

        'wait for worker to finish 
        If BWorkerLoadProp.IsBusy Then
            Threading.Thread.Sleep(1)
        End If

        loader.Close()
 End Sub

我意识到这不是很好的代码,但我已经尝试将加载器放在后台工作器中,我已经尝试过了。但无论调用什么异常。

在我做后台工作时,显示另一个更新表单的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

记录的行为难以复制 线程切换之间的某些内容可能会导致在OnFrameChanged中关闭调用后调用btnSlowSearch_Click

在任何情况下,逻辑似乎建议在显示动画的表单的close事件中调用ImageAnimator.StopAnimate

所以看看上面的评论,我会将以下内容添加到您的动画制作表单

// Not needed
// Public loader As New Loading

Private Sub OnFrameChanged(ByVal o As Object, ByVal e As EventArgs)
    Try  
        Me.Invalidate()
        If m_IsAnimating Then
            ImageAnimator.UpdateFrames()
            Me.Refresh()
            'Draw the next frame in the animation.
            Dim aGraphics As Graphics = PictureBox1.CreateGraphics
             aGraphics.DrawImage(_AnimatedGif, New Point(0, 0))
                            aGraphics.Dispose()
        End If
    Catch ex As InvalidOperationException
       .. do not leave this empty or remove altogether
    End Try
End Sub

Private Sub Form_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing

   ... if you need to stop the closing you should do it here without stopping the animation

   If m_IsAnimating Then
        ImageAnimator.StopAnimate(AnimatedGif, _
                      New EventHandler(AddressOf Me.OnFrameChanged)) 


        m_isAnimating = False
   End If
End Sub 

答案 1 :(得分:1)

这当然不是唯一的方法,但我会为您提供最简单的工作示例,希望它能帮助您纠正自己的应用程序。

1)创建一个新的vb.net Windows窗体应用程序,并在窗体上添加一个按钮(Button1)。

2)将Form1代码更改为:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If fLoading Is Nothing Then  ' can only show one loading screen at a time
            Dim oLoadingThread As clsLoadingThread = New clsLoadingThread   ' creat new thread
            oLoadingThread.ShowWaitScreen() ' show the loading screen

            '-----------------------------------------
            ' your real processing would go here
            '-----------------------------------------
            For i As Int32 = 0 To 999999
                Application.DoEvents()
            Next
            '-----------------------------------------

            oLoadingThread.CloseLoadingScreen()    ' we are done processing so close the loading form
            oLoadingThread = Nothing    ' clear thread variable
        End If
    End Sub
End Class

Public Class clsLoadingThread
    Dim oThread As System.Threading.Thread

    Private Delegate Sub CloseLoadingScreenDelegate()

    Public Sub ShowWaitScreen()
        ' create new thread that will open the loading form to ensure animation doesn't pause or stop
        oThread = New System.Threading.Thread(AddressOf ShowLoadingForm)
        oThread.Start()
    End Sub

    Private Sub ShowLoadingForm()
        Dim fLoading As New frmLoading
        fLoading.ShowDialog()   ' Show loading form
        If fLoading IsNot Nothing Then fLoading.Dispose() : fLoading = Nothing ' loading form should be closed by this point but dispose of it just in case
    End Sub

    Public Sub CloseLoadingScreen()
        If fLoading.InvokeRequired Then
            ' Since the loading form was created on a seperate thread we need to invoke the thread that created it
            fLoading.Invoke(New CloseLoadingScreenDelegate(AddressOf CloseLoadingScreen))
        Else
            ' Now we can close the form
            fLoading.Close()
        End If
    End Sub
End Class

Module Module1
    Public fLoading As frmLoading
End Module

3)添加一个新表格并将其称为frmLoading。将图片框添加到表单并将图像设置为更新gif。

4)将frmLoading代码更改为:

Public Class frmLoading
    Private Sub frmLoading_Load(sender As Object, e As EventArgs) Handles Me.Load
        fLoading = Me    ' ensure that the global loading form variable is set here so we can use it later
    End Sub

    Private Sub frmLoading_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
        fLoading = Nothing   ' clear the global loading form since the form is being disposed
    End Sub
End Class

通常我会将clsLoadingThread类和Module1模块添加到他们自己的文件中,但这样可以更容易地向您显示代码。