这显然是我无法理解如何正确设置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
我意识到这不是很好的代码,但我已经尝试将加载器放在后台工作器中,我已经尝试过了。但无论调用什么异常。
在我做后台工作时,显示另一个更新表单的正确方法是什么?
答案 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模块添加到他们自己的文件中,但这样可以更容易地向您显示代码。