如果您的同步 CheckConDB() 方法可以转换为异步方法,那么您可以更轻松地等待它的结果。如果它不能是异步的,有几个选项:
(我的建议是不要在 Timer.Tick 事件中等待,因为您不知道等待的方法需要多少时间才能完成。无论如何,计时器都会滴答作响)。
使用BeginInvoke():
此方法发布到 UI 线程并且不会阻塞。你不需要检查InvokeRequired,这个方法可以安全地从同一个线程或工作线程中调用。
添加一个存储CancellationTokenSource的字段:
Private checkDbCts As CancellationTokenSource = Nothing
在Form.Load 中(或者当您决定这样做时,但在您需要与之交互的控件创建了它们的句柄之后)运行此任务,指定调用CheckConDB() 之间的间隔;传递一个由您的 CancellationTokenSource 生成的CancellationToken:
checkDbCts = New CancellationTokenSource()
Task.Run(Function() MyBGThread(1000, bgThreadCts.Token))
任务将在每次调用CheckConDB() 之前等待[Interval] 毫秒。如果Task被取消(当CancellationTokenSource.Cancel()被调用时),它将终止并退出。
当CheckConDB() 返回一个结果时,BeginInvoke() 调用ProgressUpdate 方法,根据结果的值传递一个颜色。
Private Async Function MyBGThread(interval As Integer, token As CancellationToken) As Task
token.ThrowIfCancellationRequested()
Try
While True
Await Task.Delay(interval, token)
Dim result As Boolean = CheckConDB(ConStringDB1)
Dim ctrlColor As Color = If(result, Color.Green, Color.Red)
BeginInvoke(New Action(Sub() ProgressUpdate(ctrlColor)))
End While
Catch tce As TaskCanceledException
Return
End Try
End Function
使用IProgress(Of T)委托(这是首选方法):
添加一个存放delegate的Field,保留CancellationTokeSource之前的Field声明:
Private checkDbProgress As IProgress(Of Color) = Nothing
在Form.Load() 中,创建一个新的Progress(Of T) 委托并启动任务,传递委托,设置为ProgressUpdate() 方法、一个Interval 和一个CancellationToken:
checkDbProgress = New Progress(Of Color)(Sub(c) ProgressUpdate(c))
checkDbCts = New CancellationTokenSource()
Task.Run(Function() MyBGThread(checkDbProgress, 1000, checkDbCts.Token))
MyBGThread() 被修改为接受 Progress(Of T) 对象。
它的Report() 方法将调用UI 线程中的ProgressUpdate() 方法,因为IProgress(Of T) 捕获了它被初始化的线程的SynchronizationContext,并使用指定的方法委托将消息异步分派到该线程。
Private Async Function MyBGThread(progress As IProgress(Of Color), interval As Integer, token As CancellationToken) As Task
Try
While True
Await Task.Delay(interval, token)
Dim result As Boolean = CheckConDB(ConStringDB1)
Dim ctrlColor As Color = If(result, Color.Green, Color.Red)
progress.Report(ctrlColor)
End While
Catch tce As TaskCanceledException
Return
End Try
End Function
ProgressUpdate() 方法在这两种情况下都会被调用,并且在这两种情况下它都在 UI 线程中执行:您可以在此处与 UI 元素进行交互。
Private Sub ProgressUpdate(ctrlColor As Color)
TSSPBar.BackColor = ctrlColor
TSSPBar.ForeColor = ctrlColor
End Sub