Vb.net 尝试使用Threading.Tasks.Task在用户键入时启动后台搜索,但在用户键入暂停后启动
我已经搜索过了,但是我找不到我要找的解决方案 我特别想在这个项目中使用Threading.Tasks.Task,只是为了更好地理解它 我有一个很长的XML文件,我想根据用户键入的文本进行搜索。因为它很长,所以我想等待用户停止键入250毫秒左右,然后才真正开始在后台搜索。我试图启动我的任务,让它休眠250毫秒,然后检查我的CancelTokenSource是否因为键入了另一个字符而取消。不过,我没有看到取消,所以当排队的搜索任务完成时,我最终会看到我的结果闪烁几次,在我完成键入后,一个接一个地闪烁Vb.net 尝试使用Threading.Tasks.Task在用户键入时启动后台搜索,但在用户键入暂停后启动,vb.net,.net-4.0,task,Vb.net,.net 4.0,Task,我已经搜索过了,但是我找不到我要找的解决方案 我特别想在这个项目中使用Threading.Tasks.Task,只是为了更好地理解它 我有一个很长的XML文件,我想根据用户键入的文本进行搜索。因为它很长,所以我想等待用户停止键入250毫秒左右,然后才真正开始在后台搜索。我试图启动我的任务,让它休眠250毫秒,然后检查我的CancelTokenSource是否因为键入了另一个字符而取消。不过,我没有看到取消,所以当排队的搜索任务完成时,我最终会看到我的结果闪烁几次,在我完成键入后,一个接一个地闪烁
我的代码变得一团糟,我需要重新开始,但我希望有人能给我指出正确的方向 从线程安全属性开始,该属性确定搜索何时开始。将其初始化为
Date.MaxValue
,以防止其在被要求之前运行
Private Property SearchTriggerTime As Date
Get
SyncLock SearchTriggerTimeLock
Return _SearchTriggerTime
End SyncLock
End Get
Set(value As Date)
SyncLock SearchTriggerTimeLock
_SearchTriggerTime = value
End SyncLock
End Set
End Property
Private _SearchTriggerTime As Date = Date.MaxValue
Private ReadOnly SearchTriggerTimeLock As New Object
当搜索文本框文本更改时,请将计时器设置为要开始搜索的时间。当用户快速键入时,搜索计时器将在触发前重置。在下面的代码中,如果用户清除文本框,计时器将设置为从不触发,即不搜索
Private Const SearchDelay As Integer = 250
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If TextBox1.Text <> "" Then
SearchTriggerTime = Date.Now.AddMilliseconds(SearchDelay)
Else
SearchTriggerTime = Date.MaxValue
End If
End Sub
此线程经过三种状态。第一个状态是等待启动搜索的触发时间。它每50毫秒检查一次触发时间。第二个状态是执行搜索。在搜索过程中,它会检查表单是否关闭或用户是否键入更多内容,并在这些情况下放弃搜索。在第三种状态下,如果搜索正常完成,则要求表单的原始线程显示结果。如果需要更改控件,请始终使用form.Invoke(Delegate)
在窗体线程上进行更改
我设法让它工作,它实际上看起来相当干净(我想)。 我使用的是“静态”变量,因此我可以将所有代码都保存在这个方法中,但在后续调用中仍然可以使用我的CancellationTokenSource。 我对结果非常满意,但仍然欢迎提出改进意见和注释。 实际的搜索实际上是在UI线程上进行的(我想),但我这样做是因为在XML中查找有效节点时,很容易填充树视图。我的下一个重构将是在后台线程上进行搜索(而不仅仅是250毫秒的等待),并使用TaskScheduler发布UI更新
Private Sub txtQuickSearch_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtQuickSearch.TextChanged
Static scCancelTokenSource As Threading.CancellationTokenSource
Static scCancelToken As Threading.CancellationToken
If txtQuickSearch.Text.Length >= 3 Then
If scCancelTokenSource IsNot Nothing Then
scCancelTokenSource.Cancel()
scCancelTokenSource = Nothing
End If
scCancelTokenSource = New Threading.CancellationTokenSource
scCancelToken = scCancelTokenSource.Token
Dim lfSearch = Sub()
Dim ltToken As Threading.CancellationToken = scCancelToken
Threading.Thread.Sleep(250)
If Not ltToken.IsCancellationRequested Then
Me.Invoke(Sub() DoQuickSearch(txtQuickSearch.Text))
End If
End Sub
Threading.Tasks.Task.Factory.StartNew(lfSearch, scCancelToken)
End If
End Sub
既然你“特别想在这个项目中使用Threading.Tasks.Task,只是为了更好地理解它。”你可能会遇到麻烦,并且给你指出正确的方向将与在工作中使用任务不同……等等,这个问题总是说
Threading.Tasks.Task
?我可以发誓我看到了线程.Thread
。这使我的回答完全是胡说八道。我今天没什么好注意的…丹尼尔,我很感谢你花时间发表评论,尽管这没有Hand-E-Food的那么有用。天哪,多详细的回答啊。非常感谢你抽出时间。我期待着消化它。很高兴能帮上忙。很有趣。:-)将此标记为答案,因为其中包含详细信息和工作。Oops。我认为“scCancelToken”不需要是静态的。哦,好吧。
Private Sub SearchThread()
Do Until IsDisposed
' Wait for the user to stop typing.
Do Until IsDisposed OrElse SearchTriggerTime <= Date.Now
Thread.Sleep(50)
Loop
' Search until the form is disposed, the user types more, or the search is complete.
' TODO: Initialise the search variables.
Dim SearchComplete As Boolean = False
Do Until IsDisposed OrElse SearchTriggerTime > Date.Now OrElse SearchComplete
' TODO: Insert search code here.
If condition Then SearchComplete = True
Loop
' Reset the search timer.
SearchTriggerTime = Date.MaxValue
' Only display results if the search was completed.
If SearchComplete Then Invoke(New Action(AddressOf DisplaySearchResults))
Loop
End Sub
Private Sub DisplaySearchResults()
' TODO: Display search results.
End Sub
Private Sub txtQuickSearch_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtQuickSearch.TextChanged
Static scCancelTokenSource As Threading.CancellationTokenSource
Static scCancelToken As Threading.CancellationToken
If txtQuickSearch.Text.Length >= 3 Then
If scCancelTokenSource IsNot Nothing Then
scCancelTokenSource.Cancel()
scCancelTokenSource = Nothing
End If
scCancelTokenSource = New Threading.CancellationTokenSource
scCancelToken = scCancelTokenSource.Token
Dim lfSearch = Sub()
Dim ltToken As Threading.CancellationToken = scCancelToken
Threading.Thread.Sleep(250)
If Not ltToken.IsCancellationRequested Then
Me.Invoke(Sub() DoQuickSearch(txtQuickSearch.Text))
End If
End Sub
Threading.Tasks.Task.Factory.StartNew(lfSearch, scCancelToken)
End If
End Sub