延迟后如何执行代码。
有不同的方法可以在延迟后执行代码或异步执行代码,无论是否延迟。在这里,我正在考虑一个 Timer 和 Async/Await 模式的简单实现。
Application.DoEvent()
在任何情况下都应避免调用循环。
► 使用Timer以一种或多种方法延迟单个指令或代码的执行:
您不能等待 Timer,但您可以使用创建 Timer 并在 Timer 引发其事件时执行 Action 的方法,指示指定的 Interval 已过。
后面的方法接受一个delay
值和一个Action委托作为参数。
Delay 用于设置 Timer 的 Interval,Action 表示 Timer Ticks 时将执行的代码(我在这里使用System.Windows.Forms.Timer,因为您似乎指的是 WinForms 应用程序)。
Private waitTimer As New System.Windows.Forms.Timer()
Private TimerTickHandler As EventHandler
Private Sub Wait(delay As Integer, action As Action)
waitTimer.Interval = delay
TimerTickHandler = New EventHandler(
Sub()
action.Invoke()
waitTimer.Stop()
RemoveHandler waitTimer.Tick, TimerTickHandler
End Sub)
AddHandler waitTimer.Tick, TimerTickHandler
waitTimer.Start()
End Sub
当我们需要延迟执行代码时,我们可以调用这个方法。
Action 可以是一个简单的指令:在这种情况下,Text oflabel1
将在 5 秒后设置为“Done”,而 UI Thread 继续其操作:
label1.text = "About to Start..."
Wait(5000, Sub() Me.label1.Text = "Done")
Action 也可以是一个方法:
Private Sub SetControlText(control As Control, controlText As String)
control.Text = controlText
End Sub
' Elsewhere
Wait(5000, Sub() SetControlText(Me.label1, "Done"))
当然,该SetControlText()
方法可以执行更复杂的代码,并且可以选择设置 Timer 本身,调用Wait()
.
► 使用异步/等待模式。
异步方法提供了一种方便的方法来完成可能
长时间运行的工作,而不会阻塞调用者的线程。异步方法的调用者
无需等待异步
方法完成即可恢复其工作。
简单来说,将Async 修饰符添加到方法中,允许使用Await 运算符等待异步过程终止,然后再执行后面的代码,而当前线程可以自由地继续其处理。
▬ 请注意,Async
修饰符始终应用于Function()
返回 aTask
或 a 的 a Task(Of something)
(可以是方法可以返回的任何值/引用)。
它仅适用于( ) 方法表示aSub()
时的a 。毫无例外地记住和应用这一点非常重要(除非您非常清楚其中的含义)。▬</p>
Sub
void
Event Handler
阅读有关此的文档(在上一个链接中)和这些:
Async 和 Await
不要阻塞异步代码
一个简单的Async
方法可以用来延迟一个动作的执行:
Private Async Function Wait(delay As Integer, action As Action) As Task
Await Task.Delay(delay)
action?.Invoke()
End Function
这与 Timer 功能类似,并且以类似的方式运行。不同之处在于,您可以使用Await
此方法执行异步运行的代码,并在方法返回后等待其完成运行其他代码。调用线程(此处为 UI 线程)将在Wait()
等待方法时继续其操作。
假设在Button.Click
处理程序中,我们要执行一个 Action(一个不返回值的方法)或一个 Function(一个返回值的方法),并且后面的代码应该只在这个 Action 或 Function 返回后执行:
Private Async Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
Await Wait(5000, New Action(Sub() Me.label1.Text = "Done"))
Await Wait(5000, Nothing)
' (...)
' ... More code here. It will execute after the last Await completes
End Sub
这里我们指令等待5秒,然后给一个Label的Text设置一个值,再等5秒,什么都不做,然后执行下面的代码
如果我们不需要执行一个动作,我们可以简单地使用Task.Delay():
Private Async Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
label1.text = "About to Start..."
Await Task.Delay(5000)
label1.Text = "Done"
' (...)
' ... More code here. It will execute after the last Await completes
End Sub
我们还可以使用 Async/Await 等待在ThreadPool Thread中运行的 Task 完成,调用Task.Run()来执行 Lambda 表达式中的代码:(
只是一个示例,我们不应该使用 ThreadPool Thread一个简单的任务)
Private Async Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
label1.text = "About to Start..."
Await Task.Run(Async Function()
Await Task.Delay(5000)
BeginInvoke(New Action(Sub() Me.label1.Text = "Done"))
End Function)
' (...)
' ... More code here. It will execute after the last Await completes
End Sub
另请参阅Task.ContinueWith()方法:
创建一个在目标任务完成时异步执行的延续。