Vb.net 尝试使用Threading.Tasks.Task在用户键入时启动后台搜索,但在用户键入暂停后启动

Vb.net 尝试使用Threading.Tasks.Task在用户键入时启动后台搜索,但在用户键入暂停后启动,vb.net,.net-4.0,task,Vb.net,.net 4.0,Task,我已经搜索过了,但是我找不到我要找的解决方案 我特别想在这个项目中使用Threading.Tasks.Task,只是为了更好地理解它 我有一个很长的XML文件,我想根据用户键入的文本进行搜索。因为它很长,所以我想等待用户停止键入250毫秒左右,然后才真正开始在后台搜索。我试图启动我的任务,让它休眠250毫秒,然后检查我的CancelTokenSource是否因为键入了另一个字符而取消。不过,我没有看到取消,所以当排队的搜索任务完成时,我最终会看到我的结果闪烁几次,在我完成键入后,一个接一个地闪烁

我已经搜索过了,但是我找不到我要找的解决方案

我特别想在这个项目中使用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