评论是正确的,我会为你描述其中暗示的问题
使用System.Windows.Forms.Timer
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
这将在 UI 线程上运行,并且仅适用于处理 UI 的事情(即使那样,我也不确定您是否真的可以通过 System.Threading.Timer 证明它)
创建一个新的System.Threading.Thread
hiloCertificador1 = New Thread(AddressOf crearObjeto1)
hiloCertificador1.IsBackground = True
hiloCertificador1.Start()
这现在在 UI 之外运行,是 Timer.Tick 的全部内容。因此,您已在 UI 上打勾,然后在 UI 之外创建了一个新线程。这很奇怪
调用Sub调用Sub
Public Sub crearObjeto1()
UpdateList()
End Sub
Private Sub UpdateList()
' do stuff
End Sub
冗余应该是不言而喻的
做非 UI 的东西,但遵循 Control.InvokeRequired/BeginInvoke 模式
Private Delegate Sub UpdateListDelegate()
Private Sub UpdateList()
If Me.InvokeRequired Then
Me.BeginInvoke(New UpdateListDelegate(AddressOf UpdateList))
Else
' looks like a bunch of non-UI stuff
End If
End Sub
此模式用于在 UI 上执行操作,但该块中似乎没有 UI 代码。
不使用Using 来确保正确处置IDisposable 对象
Dim conn As New SqlConnection(parametrosCon)
Dim cmd = New SqlCommand("SELECT TOP 1 * FROM COLA WHERE docentry < 8654 and enviado = 0", conn)
Dim da As New SqlClient.SqlDataAdapter(cmd)
' do stuff
cmd.Connection.Close()
DataSet.Tables("Query").Clear()
与您当前的问题无关,但也很重要。
解决方案
因此,尽管这看起来是一项崇高的工作,但您似乎在 UI 之间来回切换,而且根本不是无缘无故的,或者更准确地说,是通过一些过度设计来制造不存在的问题。整个事情可以通过一些小的改动来简化
使用System.Threading.Timer
Dim Timer2 As New System.Threading.Timer(Sub() UpdateList(), Nothing, -1, -1)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' done in Form_Load if your Timer1 is Enabled in designer
' or can be done in a Button.Click, or however you had enabled Timer1
Timer2.Change(2000, 4000) ' this will enable Timer after 2 seconds, then will tick every 4 seconds
'Timer2.Change(-1, -1) ' this is how it's disabled
End Sub
只需调用此方法,并使用Using 正确处理您的数据库对象。添加了Sub DoUiStuff(),这是该模式的正确实现方式
Private Sub UpdateList()
Timer2.Change(-1, -1)
Using conn As New SqlConnection(parametrosCon)
conn.Open()
Using cmd = New SqlCommand("SELECT TOP 1 * FROM COLA WHERE docentry < 8654 and enviado = 0", conn)
Using da As New SqlClient.SqlDataAdapter(cmd)
da.SelectCommand = cmd
da.Fill(DataSet, "Query")
For Each fila As DataRow In DataSet.Tables(0).Rows
Using cmdInner = New SqlCommand("UPDATE COLA SET enviado = 1 WHERE DOCENTRY = (@docEntry) AND TIPO = (@tipodoc)", conn)
cmd.Connection.Open()
cmd.Parameters.AddWithValue("@docEntry", fila("docentry"))
cmd.Parameters.AddWithValue("@tipodoc", fila("tipo"))
cmd.ExecuteNonQuery()
Dim factura As New FacturaCerificacion(fila("docentry"), fila("tipo"))
End Using
Next
End Using
End Using
DoUiStuff(arguments) ' for example, if you need to update a GridView
DataSet.Tables("Query").Clear()
End Using
End Sub
Private Sub DoUiStuff(arguments As Whatever)
If Me.InvokeRequired() Then
Me.Invoke(New Action(Of Whatever)(AddressOf DoUiStuff), arguments)
Else
' do UI stuff with arguments
End If
Timer2.Change(2000, -1)
End Sub
最后,我并不自相矛盾,我将添加 Dispose 方法来处理 Timer。默认情况下,此 Sub 将位于您的 Form.Designer.vb 文件中,您可以将其保留在那里,或者在添加后将其移动到 Form.vb 中。
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing Then
components?.Dispose()
Timer2?.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub