UI wird nicht upgedatet??

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    UI wird nicht upgedatet??

    Guten Morgen allerseits :)

    ich hab ein kleines Problem, es scheint, als würde mein UI nicht upgdatet, also das ist meine Vermutung, es kann aber auch was Anderes sein.

    Ich versuche, einen Downloadfortschritt mit einer ProgressBar anzuzeigen (bzw. einer TextBox), die Methode DoAny hab ich bloss zu Testzwecken, sie soll dann ersetzt werden...Leider zeigt mir die TextBox nichts an...

    Hier mein Code, wie man sieht, hab ich schon versucht, dem Problem mit .Invoke in Kombination mit asynchronen Methoden zu Leibe zu rücken, aber bei dem Thema bin ich mir noch bisschen unsicher:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private MeinDispatcher As Dispatcher
    3. Private FortSchritt As IProgress(Of String)
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. MeinDispatcher = Dispatcher.CurrentDispatcher
    6. End Sub
    7. Private Sub btnInstall_Click(sender As Object, e As EventArgs) Handles btnInstall.Click
    8. MeinDispatcher.Invoke(Sub() FortSchritt = New Progress(Of String)(Function(s) (TextBox1.Text, s)))
    9. DoAny(FortSchritt).GetAwaiter.GetResult()
    10. MessageBox.Show("fertig")
    11. End Sub
    12. Private Async Function DoAny(p As IProgress(Of String)) As Task(Of Boolean)
    13. Dim x As Integer = 0
    14. For i = 1 To 500000000
    15. If i Mod 10000 = 0 Then
    16. MeinDispatcher.Invoke(Sub() p.Report(x.ToString))
    17. End If
    18. x += 1
    19. Next
    20. Return True
    21. End Function
    Deine DoAny: Async ohne Await ergibt keinen Sinn. Das hätte bei richtigen Einstellungen VS aber schon anmeckern sollen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Jou tut es auch.

    Ich hab jetzt das hier, nur sagt er da "Option Strict on lässt spätes Binden nicht zu". Wenn ich es ausschalte, dann kommt: Der Lambdaparamter p verbirgt eine Variable in einem einschliessenden Block, eine zuvor definierte Bereichsvariable oder eine implizit im Abfrageausdruck deklarirte Variable:

    VB.NET-Quellcode

    1. ​Private Async Function DoAny(p As IProgress(Of String)) As Task(Of Boolean)
    2. Dim x As Integer = 0
    3. For i = 1 To 500000000
    4. If i Mod 10000 = 0 Then
    5. 'p.Report(x.ToString)
    6. Await MeinDispatcher.Invoke(Function(p) p.Report(x.ToString))
    7. End If
    8. x += 1
    9. Next
    10. Return True
    11. End Function
    Dann mach Await MeinDispatcher.Invoke(Function(wasauchimmer) wasauchimmer.Report(x.ToString))
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Du hättest mich tatsächlich wörtlich nehmen sollen.
    Du hast

    VB.NET-Quellcode

    1. Await MeinDispatcher.Invoke(Function(p) p.Report(x.ToString))
    geschrieben. Du verwendest also p in der lokalen Lambdafunktion und mit

    VB.NET-Quellcode

    1. Private Async Function DoAny(p As IProgress(Of String)) As Task(Of Boolean)
    in der umliegenden Funktion als Funktionsparameter. Nun weiß der Compiler nicht, was Du mit p meinst. Benenne den Lambdafunktionsparameter um: von p in wasauchimmer. Oder von p in q oder in asdf. Aber ändern musst Du es.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Okay das versteh ich. Aber dann stimmt wahrscheinlich die ganze Zeile nicht. Weil irgendwas will ich ja mit meinem p (also das Argument der Methode DoAny) machen.

    Schau dir dazu mal die auskommentierte Zeile an. So sollte das eigentlich sein, wenn man das ganze Async und Dispatcher Gedöns weglässt.

    Gibt's vielleicht eine Alternative, wie man diese auskommentierte Zeile mit Await von MeinDispatcher invoken kann? Weisst du wie ich mein? Ohne Sub und Function.
    Probier das mal. Ist zwar etwas anders, aber sollte vom Prinzip her reichen.

    VB.NET-Quellcode

    1. Private ReadOnly ProgressReporter As New Progress(Of Long)(Sub(x) ReportProgressUpdate(x))
    2. Private ReadOnly AbstractProgressReporter As IProgress(Of Long) = ProgressReporter
    3. Private Sub ReportProgressUpdate(x As Long)
    4. TextBox1.Text = x.ToString
    5. End Sub
    6. Private Async Sub btnInstall_Click(sender As Object, e As EventArgs) Handles btnInstall.Click
    7. Await Task.Run(Sub() DoHeavyWork())
    8. MessageBox.Show("fertig")
    9. End Sub
    10. Private Sub DoHeavyWork()
    11. For i = 1 To 500000000
    12. If i Mod 100000 = 0 Then AbstractProgressReporter.Report(i)
    13. Next
    14. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Okay danke das funktioniert schon mal.

    Jetzt versuch ich das Ganze mit der Downloadfunktion zu machen, da bekomm ich aber für totalBytes in Zeile 6 immer -1
    zurück... Weiss jemand woran das liegen kann?

    VB.NET-Quellcode

    1. Module HttpClientExtensions
    2. <Extension>
    3. Public Async Function DownloadAsync(client As HttpClient, url As String, fileStream As MemoryStream, progress As Progress(Of Long), cancellationToken As CancellationToken) As Task
    4. Using response As HttpResponseMessage = Await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)
    5. Using contentStream As Stream = Await response.Content.ReadAsStreamAsync()
    6. Dim totalBytes As Long = response.Content.Headers.ContentLength.GetValueOrDefault(-1)
    7. Dim bytesRead As Long = 0
    8. Dim buffer(4096) As Byte
    9. Dim bytesReadThisChunk As Integer
    10. While (bytesReadThisChunk = Await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0
    11. Await fileStream.WriteAsync(buffer, 0, bytesReadThisChunk, cancellationToken)
    12. bytesRead += bytesReadThisChunk
    13. If totalBytes > 0 Then
    14. Dim progressPercentage As Single = CSng(bytesRead) / CSng(totalBytes)
    15. Form1.AbstractProgressReporter.Report(progressPercentage)
    16. End If
    17. End While
    18. End Using
    19. End Using
    20. End Function

    kafffee schrieb:

    Form1.AbstractProgressReporter.Report(progressPercentage)
    ;( Ich weiß nicht, ob ich wissen will, was Form1 ist …

    Aber zurück zum Problem. Das ist nicht Dein Code, oder? Denn wenn es Dein eigener Code wäre, hättest Du nicht soviel geschrieben, nur um bereits so früh nicht zu einem sinnvollen Zwischenergebnis zu kommen. Daher: Quelle des Codes?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    In der Tat :)

    Wenn ich mich richtig erinnere hat mir das die KI von Bing als erstes in den Suchergebnissen geliefert... Aber das hier ist so ähnlich:

    stackoverflow.com/questions/20…gress-bar-with-httpclient

    Edit: Ich glaub das liegt gar nicht an dem Code, die URL die ich abrufe, ist eine von mir in meiner Cloud freigebene Datei. Mir ist aber grad eingefallen, dass die Cloud immer erst noch eine "Zwischenseite" (müsste HTML sein) aufruft, wenn man auf den Link klickt. Hat jemand ne Idee mit welcher URL ich das sinnvoll testen könnte?

    @VaporiZed
    Edit:

    Hab jetzt das hier gefunden, und es funktioniert :-). Es bleibt aber die Frage: Weiss jemand wie ich an ne URL komme, die gross genug ist, dass ich das cts.Cancel mal testen kann? Weil bevor ich auf Abbrechen klicken kann, ist die Show schon vorbei...

    VB.NET-Quellcode

    1. Public Delegate Sub ProgressChangedHandler(ByVal totalFileSize As Long?, ByVal totalBytesDownloaded As Long, ByVal progressPercentage As Double?)
    2. Public Class HttpClientWithProgress
    3. Inherits HttpClient
    4. Private ReadOnly _DownloadUrl As String
    5. Private ReadOnly _DestinationFilePath As String
    6. Public Event ProgressChanged As ProgressChangedHandler
    7. Public Sub New(ByVal downloadUrl As String, ByVal destinationFilePath As String)
    8. _DownloadUrl = downloadUrl
    9. _DestinationFilePath = destinationFilePath
    10. End Sub
    11. Public Async Function StartDownload() As Task
    12. Using response = Await GetAsync(_DownloadUrl, HttpCompletionOption.ResponseHeadersRead)
    13. Await DownloadFileFromHttpResponseMessage(response)
    14. End Using
    15. End Function
    16. Public Async Function StartDownload(ByVal cancellationToken As CancellationToken) As Task
    17. Using response = Await GetAsync(_DownloadUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
    18. Await DownloadFileFromHttpResponseMessage(response)
    19. End Using
    20. End Function
    21. Private Async Function DownloadFileFromHttpResponseMessage(ByVal response As HttpResponseMessage) As Task
    22. response.EnsureSuccessStatusCode()
    23. Dim totalBytes As Long? = response.Content.Headers.ContentLength
    24. Using contentStream = Await response.Content.ReadAsStreamAsync()
    25. Await ProcessContentStream(totalBytes, contentStream)
    26. End Using
    27. End Function
    28. Private Async Function ProcessContentStream(ByVal totalDownloadSize As Long?, ByVal contentStream As Stream) As Task
    29. Dim totalBytesRead As Long = 0L
    30. Dim readCount As Long = 0L
    31. Dim buffer As Byte() = New Byte(8191) {}
    32. Dim isMoreToRead As Boolean = True
    33. 'Using fileStream As FileStream = New FileStream(_DestinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, True)
    34. Using fileStream As MemoryStream = New MemoryStream
    35. Do
    36. Dim bytesRead As Integer = Await contentStream.ReadAsync(buffer, 0, buffer.Length)
    37. If bytesRead = 0 Then
    38. isMoreToRead = False
    39. Continue Do
    40. End If
    41. Await fileStream.WriteAsync(buffer, 0, bytesRead)
    42. totalBytesRead += bytesRead
    43. readCount += 1
    44. If readCount Mod 10 = 0 Then TriggerProgressChanged(totalDownloadSize, totalBytesRead)
    45. Loop While isMoreToRead
    46. End Using
    47. TriggerProgressChanged(totalDownloadSize, totalBytesRead)
    48. End Function
    49. Private Sub TriggerProgressChanged(ByVal totalDownloadSize As Long?, ByVal totalBytesRead As Long)
    50. 'If ProgressChanged Is Nothing Then Return
    51. Dim progressPercentage As Double? = Nothing
    52. If totalDownloadSize.HasValue Then progressPercentage = Math.Round(CDbl(totalBytesRead) / totalDownloadSize.Value * 100, 2)
    53. RaiseEvent ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage)
    54. End Sub
    55. End Class

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „kafffee“ ()

    Such mal im Netz nach Gigantic Test Image, z.B. dieses 96 MB Bild
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.