OBLIVION LIGHT Ответов: 0

Как предотвратить отмену cancellationtoken во время загрузки строки


Я заполняю список из строки асинхронной загрузки с помощью httpclient.
Список немного изменен, так как мне нужно было событие прокрутки, и я нашел в интернете действительно классный класс для него.
Код класса Listbox:

Public Class BetterListBox
    Inherits ListBox

    ' Event declaration
    Public Delegate Sub BetterListBoxScrollDelegate(ByVal Sender As Object, ByVal e As BetterListBoxScrollArgs)
    Public Event Scroll As BetterListBoxScrollDelegate
    ' WM_VSCROLL message constants
    Private Const WM_VSCROLL As Integer = &H115
    Private Const SB_THUMBTRACK As Integer = 5
    Private Const SB_ENDSCROLL As Integer = 8

    Protected Overrides Sub WndProc(ByRef m As Message)
        ' Trap the WM_VSCROLL message to generate the Scroll event
        MyBase.WndProc(m)

        If m.Msg = WM_VSCROLL Then
            Dim nfy As Integer = m.WParam.ToInt32() And &HFFFF
            If (nfy = SB_THUMBTRACK OrElse nfy = SB_ENDSCROLL) Then
                RaiseEvent Scroll(Me, New BetterListBoxScrollArgs(Me.TopIndex, nfy = SB_THUMBTRACK))
            End If
        End If
    End Sub
    Public Class BetterListBoxScrollArgs
        ' Scroll event argument
        Private mTop As Integer
        Private mTracking As Boolean
        Public Sub New(ByVal top As Integer, ByVal tracking As Boolean)
            mTop = top
            mTracking = tracking
        End Sub
        Public ReadOnly Property Top() As Integer
            Get
                Return mTop
            End Get
        End Property
        Public ReadOnly Property Tracking() As Boolean
            Get
                Return mTracking
            End Get
        End Property
    End Class
End Class



Я заполняю список с помощью:
    Private downloader As MyDownloader = Nothing

Private Sub btnStartDownload_Click(sender As Object, e As EventArgs) Handles btnStartDownload.Click
    Dim progress = New Progress(Of String)(
        Sub(data)
            ' We're on the UI Thread here
            ListBox1.Items.Clear()
            ListBox1.Items.AddRange(Split(data, vbLf))
            RichTextBox1.SelectionStart = RichTextBox1.TextLength
        End Sub)

    Dim url As Uri = New Uri("https://SomeAddress.com")
    downloader = New MyDownloader()
    ' Download from url every 1 second and report back to the progress delegate
    downloader.StartDownload(progress, url, 1)

Private Async Sub btnStopDownload_Click(sender As Object, e As EventArgs) Handles btnStopDownload.Click
    Await downloader.StopDownload()
End Sub


И вспомогательный класс:

Imports System.Diagnostics
Imports System.Net
Imports System.Net.Http
Imports System.Text.RegularExpressions
Imports System.Threading

Public Class MyDownloader
    Private Shared ReadOnly client As New HttpClient()
    Private ReadOnly cts As CancellationTokenSource = New CancellationTokenSource()
    Private interval As Integer = 0

    Public Sub StartDownload(progress As IProgress(Of String), url As Uri, intervalSeconds As Integer)
        interval = intervalSeconds * 1000
        Task.Run(Function() DownloadAsync(progress, url, cts.Token))
    End Sub

    Private Async Function DownloadAsync(progress As IProgress(Of String), url As Uri, token As CancellationToken) As Task
        Dim responseData As String = String.Empty
        Dim pattern As String = "<(?:[^>=]|='[^']*'|=""[^""]*""|=[^'""][^\s>]*)*>"
        Dim downloadTimeWatch As Stopwatch = New Stopwatch()
        downloadTimeWatch.Start()
        Do
            If cts.IsCancellationRequested Then Return
            Try
                Using response = Await client.GetAsync(url, HttpCompletionOption.ResponseContentRead, token)
                    responseData = Await response.Content.ReadAsStringAsync()
                    responseData = WebUtility.HtmlDecode(Regex.Replace(responseData, pattern, ""))
                End Using
                progress.Report(responseData)

                Dim delay = interval - CInt(downloadTimeWatch.ElapsedMilliseconds)
                Await Task.Delay(If(delay <= 0, 10, delay), token)
                downloadTimeWatch.Restart()
            Catch tcEx As TaskCanceledException
                ' Don't care - catch a cancellation request
                Debug.Print(tcEx.Message)
            Catch wEx As WebException
                ' Internet connection failed? Internal server error? See what to do
                Debug.Print(wEx.Message)
            End Try
        Loop
    End Function

    Public Async Function StopDownload() As Task
        Try
            cts.Cancel()
            client?.CancelPendingRequests()
            Await Task.Delay(interval)
        Finally
            client?.Dispose()
            cts?.Dispose()
        End Try
    End Function
End Class


Что я уже пробовал:

Итак, я использую Await downloader.StopDownload() в listbox scroll event и mouse enter, а в listbox mouseleave eventI снова начинаю загрузку.
Проблема в том, что во время прокрутки я получаю сообщение об ошибке : System.ObjectDisposedException: "CancellationTokenSource был отменен". Я пытался использовать try catch напрасно , событие listbox mouseleave не запускает загрузку снова... У кого-нибудь есть идеи? Спасибо

0 Ответов