【问题标题】:Closing form with Gif throws InvalidOperationException使用 Gif 关闭表单会引发 InvalidOperationException
【发布时间】:2015-02-20 22:19:12
【问题描述】:

这显然是我不了解如何正确设置 UI 线程的问题,但我不知道如何修复它。

我有一个 datagridview,我在其中单击一个按钮,从网络获取信息,然后将其与新数据一起显示在 datagridview 上。当它在网络上时,我有一个带有更新 gif 的表格,我称之为“加载”表格。在该表单中,我使用 Internet 上的典型 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

我意识到这不是很好的代码,但我尝试将加载程序放在后台工作程序中,我尝试了任何方法。但无论异常被称为什么。

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

【问题讨论】:

  • 调用 loader.Close() 后,loader 对象不再可用。所以你第二次点击按钮时,你的程序总是会爆炸。摆脱As New,您必须使用New 运算符显式创建一个新的Loading 实例。
  • 所以“公共加载器 = 新加载”?
  • 不,公共加载器作为加载。在您的 Click 事件处理程序中:loader = New Loading
  • 抱歉,但是在单击事件中的“公共加载程序作为加载”和加载程序 = 新加载“的设置中仍然会引发异常。所以我的表单实际上从未显示在我的 gui 上
  • 是否有可能在btnSlowSearch_Click 中调用关闭后调用您的OnFrameChanged?我不确定,但逻辑似乎建议在显示动画的表单的关闭事件中调用 ImageAnimator.StopAnimate。

标签: vb.net multithreading user-interface datagridview


【解决方案1】:

记录的行为很难重现。
线程切换之间的某些事情可能会导致在调用btnSlowSearch_Click 中关闭之后调用OnFrameChanged

无论如何,逻辑似乎建议在显示动画的表单的关闭事件中调用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 

【讨论】:

  • 我有一些更简单的东西,但我在这里将其更改为您的设置,因为它看起来是更聪明的方法。我刚刚测试成功了!
【解决方案2】:

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

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 模块添加到它们自己的文件中,但这样向您显示代码会更容易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    相关资源
    最近更新 更多