Optimierung und Probleme mit Dateidownload

  • VB.NET

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von Nic.

    Optimierung und Probleme mit Dateidownload

    Guten Abend,

    ich sitze zurzeit an einem Programm welches immer 4 feste Dateien aktualisieren soll. Bei jedem Start des Programms werden die Zahlen von vier Textdokumenten (welche auf einem Webspace liegen | Ein Textdokument = eine der vier Dateien) in einer Variable gespeichert. Um an die lokale Version ran zu kommen wird mithilfe von GetSetting die lokale Version aus der Registry bezogen (auch viermal da vier verschiedene Dateien). Nun wird überprüft ob ob die Webversionszahl größer als die Lokaleversionszahl ist, wenn ja dann wird eine MarkerVariable = 1 gesetzt. Am Ende wird dann bei jeder Datei gefragt ob der dazugehörige Marker = 1 ist, wenn ja dann muss die Datei aktualisiert werden. Kommen wir zu meinen zwei Problemen. Das erste Problem wäre die Optimierung des Codes... ich kann mir nicht vorstellen das dies besonders sauber ist wie ich es gemacht hab:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Main
    2. Public Shared DateiC_Web As String
    3. Public Shared DateiD_Web As String
    4. Public Shared DateiM_Web As String
    5. Public Shared DateiY_Web As String
    6. Public Shared DateiC_Local As String
    7. Public Shared DateiD_Local As String
    8. Public Shared DateiM_Local As String
    9. Public Shared DateiY_Local As String
    10. Public Shared ProgressbarFortschritt As Double = 100
    11. Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    12. Dim DateiC_Marker As Double
    13. Dim DateiD_Marker As Double
    14. Dim DateiM_Marker As Double
    15. Dim DateiY_Marker As Double
    16. Dim DateiGesamtMarker As Double
    17. Using wc As New Net.WebClient()
    18. DateiC_Web = wc.DownloadString("http://update.webseite.de/datei-c.txt")
    19. DateiC_Local = GetSetting("Programm", "DateiVersionen", "Datei-C")
    20. If DateiC_Web > DateiC_Local Then
    21. DateiC_Marker = 1
    22. End If
    23. DateiD_Web = wc.DownloadString("http://update.webseite.de/datei-d.txt")
    24. DateiD_Local = GetSetting("Programm", "DateiVersionen", "Datei-D")
    25. If DateiD_Web > DateiD_Local Then
    26. DateiD_Marker = 1
    27. End If
    28. DateiM_Web = wc.DownloadString("http://update.webseite.de/datei-m.txt")
    29. DateiM_Local = GetSetting("Programm", "DateiVersionen", "Datei-M")
    30. If DateiM_Web > DateiM_Local Then
    31. DateiM_Marker = 1
    32. End If
    33. DateiY_Web = wc.DownloadString("http://update.webseite.de/datei-y.txt")
    34. DateiY_Local = GetSetting("Programm", "DateiVersionen", "Datei-Y")
    35. If DateiY_Web > DateiY_Local Then
    36. DateiY_Marker = 1
    37. End If
    38. End Using
    39. DateiGesamtMarker = DateiC_Marker + DateiD_Marker + DateiM_Marker + DateiY_Marker
    40. If DateiGesamtMarker > 0 Then
    41. btnStartProgram.Enabled = False
    42. pgbDownloadEinzel.Value = 0 //Fortschritt einer Datei
    43. pgbDownloadGesamt.Value = 0 //Gesamter Fortschritt der Aktualisierung
    44. ProgressbarFortschritt = ProgressbarFortschritt / DateiGesamtMarker //Die gesamte Progressbar (Value=100) wird durch die Anzahl der nötigen Aktualisierungen geteilt. Das Ergebnis ist die Zahl
    45. die nach jedem erfolgreichen Download zu der Gesamtprogressbar gezählt wird. (Zum Beispiel wenn zwei Dateien aktualisiert
    46. werden müssen wird 100 / 2 geteilt was 50 ergibt. Also wird nach jedem erfolgreichen Download pgbDownloadGesamt.Value =
    47. pgbDownloadGesamt.Value + ProgressbarFortschritt gerechnet.
    48. If DateiC_Marker = 1 Then
    49. pgbDownloadEinzel.Value = 0
    50. DateiC_Download.DownloadFileAsync(New Uri("http://update.webseite.de/datei-c.dat"), "datei-c.dat") // Funktioniert nicht
    51. SaveSetting("Programm", "DateiVersionen", "Datei-C", DateiC_Web)
    52. pgbDownloadGesamt.Value = pgbDownloadGesamt.Value + ProgressbarFortschritt
    53. End If
    54. If DateiD_Marker = 1 Then
    55. pgbDownloadEinzel.Value = 0
    56. DateiD_Download.DownloadFileAsync(New
    57. Uri("http://update.webseite.de/datei-d.dat"), "datei-d.dat") //
    58. Funktioniert nicht
    59. SaveSetting("Programm", "DateiVersionen", "Datei-D", DateiD_Web)
    60. pgbDownloadGesamt.Value = pgbDownloadGesamt.Value + ProgressbarFortschritt
    61. End If
    62. If DateiM_Marker = 1 Then
    63. pgbDownloadEinzel.Value = 0
    64. DateiM_Download.DownloadFileAsync(New
    65. Uri("http://update.webseite.de/datei-m.dat"), "datei-m.dat") //
    66. Funktioniert nicht
    67. SaveSetting("Programm", "DateiVersionen", "Datei-M", DateiM_Web)
    68. pgbDownloadGesamt.Value = pgbDownloadGesamt.Value + ProgressbarFortschritt
    69. End If
    70. If DateiY_Marker = 1 Then
    71. pgbDownloadEinzel.Value = 0
    72. DateiY_Download.DownloadFileAsync(New
    73. Uri("http://update.webseite.de/datei-y.dat"), "datei-y.dat") //
    74. Funktioniert nicht
    75. SaveSetting("Programm", "DateiVersionen", "Datei-Y", DateiY_Web)
    76. pgbDownloadGesamt.Value = pgbDownloadGesamt.Value + ProgressbarFortschritt
    77. End If
    78. btnStartProgram.Enabled = True
    79. End If
    80. pgbDownloadEinzel.Value = 100
    81. pgbDownloadGesamt.Value = 100
    82. End Sub



    Was kann man da alles optimieren? Es ist wichtig die 4 Dateien einzeln zu behandeln da es z.B. vorkommen kann das nur Datei-Y und Datei-M aktualisiert werden müssen. Des Weiteren wie schon im Code ersichtlich habe ich ein Problem mit dem Kern des Programmes... dem Download. Soweit Google die Wahrheit sagt gibt es zwei Arten von Downloads. Einmal der Download via HTTPRequest welcher aber das Programm während des Downloads einfriert und einmal der Asynchrone Download. Es wäre wichtig das die Downloads direkt hintereinander erfolgen also zum Beispiel:

    Datei-C und Datei-M haben eine höhere Webversion als die lokale Version. Also wird erst Datei-C gedownloadet (die Einzelprogressbar beginnt bei 0 und füllt sich mit dem Download, das Programm pausiert an der Stelle bis zum Ende, ist aber nicht eingefroren) und dann die Gesamtprogressbar auf 50 gesetzt (weil 100 / 2 = 50). Danach wird die Datei-M gedownloadet (die Einzelprogressbar setzt sich zurück und beginnt wieder sich zu füllen, genau das gleiche wie zuvor bei Datei-C).


    Ich habe bereits mehrere Lösungen probiert doch fror mir entweder das Programm ein, die Downloads liefen nicht hintereinander oder es war nicht möglich eine Progressbar einzubinden. Langsam verzweifel ich...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nic“ ()

    ist ja interessant: Logik-mäßig dasselbe Problem wie hier: [VB.NET] Verzweifele beim Vergleichen zweier Arrays.

    Man müsste es wirklich mal generisch und einfürallemal ausprogrammieren, eine Function, der man die alte und die neue Liste übergibt, und die 3 Listen zurückgibt: eine mit Deletes, eine mit Modifieds und eine mit Addeds.

    Dein konkretes Prob hab ich nicht verstanden: kriegst du den Download einer Datei nicht gebacken? gugge vlt async HTTP FTP-Download
    Du hast Dir jedenfalls Mühe bei Deiner Problembeschreibung gegeben, das alleine verdient schon eine Antwort ;)

    Also ein paar Bemerkungen hierzu:
    - das Festhalten in 'Markern' scheint überflüssig: wenn ein Update notwendig ist, so trag die WebAdresse der entsprechenden Datei in eine 'Update-Liste' ein, oder lade gleich
    - 2 Progressbars scheinen mir genauso übertrieben, auch vom Design her: versuch das evtl auf 1 zu reduzieren
    - ggf. kann man in einer abgewandelten Progressbar den Dateinamen des aktuellen Downloads anzeigen lassen, oder nimmt gleich den Marquee-Style

    Nic schrieb:

    Soweit Google die Wahrheit sagt gibt es zwei Arten von Downloads. Einmal der Download via HTTPRequest welcher aber das Programm während des Downloads einfriert und einmal der Asynchrone Download. Es wäre wichtig das die Downloads direkt hintereinander erfolgen also zum Beispiel:

    Es gibt grundsätzlich 2 Arten von Downloads:
    - synchron: der Code/Thread stoppt bist die Ausführung beendet ist: darunter fällt z.B. WebClient.DownloadString
    - asynchron: der Download wird ausgelöst, läuft aber auf einem anderen Thread: z.B. WebClient.DownloadFileAsync

    Warum ist es Dir wichtig, dass die Downloads nacheinander ablaufen, nur aufgrund der Progressbars ?

    So oder so sollte die Prüfung und der Download der Files in einem anderen Thread als dem GUI-Thread ablaufen: auch WebClient.DownloadString führt zum Lag bei der GUI, z.B. dem Ziehen der Form.

    Lagere Deinen ganzen Code in einen Thread oder einen BackgroundWorker aus und lade die Files dort synchron. Dort wird der GUI-Thread nicht beeinflusst. Zum Update der Progressbar wirst Du invoken müssen (s.u.). Den Abschluss des Ladens kannst Du dann mit einem Event signalisieren.
    Vielleicht hilft Dir folgendes Beispiel weiter: Progressbar und Timer im extra Thread

    @EDR

    ErfinderDesRades schrieb:

    an müsste es wirklich mal generisch und einfürallemal ausprogrammieren
    Was möchtest Du 'generisch ausprogrammieren' ? Etwas was LINQ in 3 Queries schafft, bzw in einem etwas länglichen 1-Zeiler ? Have fun ...
    Ein paar Anmerkungen zur Optimierung:
    1. Nutze keine Shared-Variablen.
    Auch wenn es so scheinbar einfach ist, Informationen zwischen verschiedenen Instanzen auszutauschen, ziehen wir doch die Kapselung von Daten vor. Nutze Properties, um Daten zu lesen oder zu verändern, nutze Events, um Vorgänge auszulösen.
    2. Meide die Form_Load für Daten-Processing.
    Eine Reihe von Exceptions, die in der Form_Load auftreten, werden nicht als Exception angezeigt, sondern führen lediglich zum vorzeitigen Abbruch der Form_Load und zur normalen Fortsetzung des Programms. Davon, dass da Code nicht ausgeführt wurde, merkst Du dann zunächst nix, darauf aufbauende Prozeduren greifen dann ggf. ins Leere.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Wenn ich Form_Load nicht benutzen sollte, was sollte ich dann benutzen? Ich möchte ja nicht das der Benutzer erst auf einen Button klickt...

    Des Weiteren verstehe ich nicht ganz deine Anmerkung zu den Public Variablen. Da ich noch eine andere Form habe welche auf die Variablen zugreift wüsste ich keine andere Methode.

    Ich werde vorerst bei einer Progressbar bleiben, doch wäre es einfach angenehmer wenn nachdem erfolgreichen Download einer Datei (falls noch eine weitere Datei aktualisiert werden muss), direkt der Download der nächsten Datei erfolgt.

    Nic schrieb:

    was sollte ich dann benutzen?
    Probiere mal

    VB.NET-Quellcode

    1. Private Sub Form1_Shown(sender As System.Object, e As System.EventArgs) Handles MyBase.Shown
    2. MessageBox.Show("Form1_Shown")
    3. End Sub
    Falls Du mehrfach Visible umschaltest, solltest Du Dir eine FirstCall-Variable gönnen.

    Nic schrieb:

    zu den Public Variablen.

    RodFromGermany schrieb:

    Nutze keine Shared-Variablen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Nic schrieb:

    Wenn ich Form_Load nicht benutzen sollte, was sollte ich dann benutzen? Ich möchte ja nicht das der Benutzer erst auf einen Button klickt...
    Nun, ich würde erst einmal FormLoad benutzen. Allerdings sollten die Buttons auf Enabled=False stehen, so kann der Benutzer sie auch nicht klicken.

    Nic schrieb:

    Des Weiteren verstehe ich nicht ganz deine Anmerkung zu den Public Variablen. Da ich noch eine andere Form habe welche auf die Variablen zugreift wüsste ich keine andere Methode.
    Du kannst auch ohne Shared auf die Variablen zugreifen, wenn sie denn Public sind.

    Nic schrieb:

    doch wäre es einfach angenehmer wenn nachdem erfolgreichen Download einer Datei (falls noch eine weitere Datei aktualisiert werden muss), direkt der Download der nächsten Datei erfolgt.
    Das Problem hier ist: ein synchroner Download mit dem WebClient meldet keinen Fortschrit, insofern muss der Download asynchron erfolgen. Auf der anderen Seite möchtest Du die Dateien nacheinander laden um eine vernünftige Fortschrittsanzeige zu besitzen. Insofern muss man künstlich stoppen

    Falls Deine Filenamen so sind wie beschrieben, sollte in etwa folgendes hinhauen.

    "Beispielcode"

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Imports System.Net
    3. Public Class Form1
    4. ' DateiNamen
    5. Public fileNames As String() = {"Datei-A", "Datei-B", "Datei-C", "Datei-D"}
    6. ' threading
    7. Private t As Thread
    8. Private Event ThreadFinished()
    9. ' ein waithandle zum Anhalten des Threads
    10. Private waitHandle As New AutoResetEvent(False)
    11. ' der webclient
    12. Private WithEvents wc As WebClient
    13. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    14. ' PrüfThread starten: Buttons sollten auf Disabled stehen
    15. t = New Thread(Sub() checkFiles()) With {.IsBackground = True, .Name = "CheckFiles Thread"}
    16. t.Start()
    17. End Sub
    18. Private Sub checkFiles()
    19. ' gesamtfortschritt auf 0
    20. Me.Invoke(Sub() pgbDownloadGesamt.Value = 0)
    21. ' filenames durchlaufen
    22. Using wc As New Net.WebClient()
    23. For Each filename As String In fileNames
    24. ' web txt-datei holen
    25. Dim webFileSettings As String = wc.DownloadString(String.Format("http://update.webseite.de/{0}.txt", filename))
    26. Dim localFileSettings As String = GetSetting("Programm", "DateiVersionen", filename)
    27. ' progressbar zurücksetzen
    28. Me.Invoke(Sub() pgbDownLoadEinzel.Value = 0)
    29. ' download nötig ?
    30. If localFileSettings < webFileSettings Then
    31. ' webFile laden: da das synchrone Laden keinen Fortschritt meldet müssen wir asynchron laden
    32. Dim datFile As String = String.Format("{0}.dat", filename)
    33. wc.DownloadFileAsync(New Uri(String.Format("http://update.webseite.de/{0}", datFile)), datFile)
    34. ' wir stoppen den thread bis der download fertig ist
    35. waitHandle.WaitOne()
    36. ' fertig: neue settings setzen
    37. SaveSetting("Programm", "DateiVersionen", filename, webFileSettings)
    38. End If
    39. ' gesamtfortschritt anzeigen
    40. Me.Invoke(Sub() pgbDownloadGesamt.Value += 100 \ fileNames.Length)
    41. Next
    42. End Using
    43. ' fertig: Event auf dem GUI Thread auslösen
    44. Me.Invoke(Sub() RaiseEvent ThreadFinished())
    45. End Sub
    46. ' webclient fortschrit
    47. Private Sub OnWebclientUpdate(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
    48. ' wir sind auf einem anderen Thread als dem GUI-Thread, also invoke
    49. Me.Invoke(Sub() pgbDownLoadEinzel.Value = e.ProgressPercentage )
    50. End Sub
    51. ' webclient fertig
    52. Private Sub OnWebClientFinished(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
    53. ' wir sind auf einem anderen Thread als dem GUI-Thread, also invoke
    54. Me.Invoke(Sub() pgbDownLoadEinzel.Value = 0)
    55. ' thread aufwecken
    56. waitHandle.Set()
    57. End Sub
    58. ' thread fertig
    59. Private Sub OnThreadFinished() Handles Me.ThreadFinished
    60. ' Progressbars auf 0
    61. pgbDownLoadEinzel.Value = 0
    62. pgbDownloadGesamt.Value = 0
    63. ' BUTTONS auf ENABLED stellen
    64. End Sub
    65. End Class


    Da ungetestet, kann der Code Fehler enthalten. Dann mit dem Debugger Breakpoints setzen und im Einzelschritt ausführen.Wie Du Dir vorstellen kansst wäre der Code ohne die Fortschrittsanzeige erheblich kürzer, das ständige Invoke aus dem Thread würde dann wegfallen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Kangaroo“ ()

    Das Programm läuft bis zu der ForEach Schleife, da springt er komischerweise nicht rein. Als Ergebnis ist wenn das Programm gestartet wird nach 1 Sekunde immer noch der Button disabled, die pgbGesamt = 0 und die pgbEinzel = 100. Ich bin schon im Debug Modus durch gegangen, da springt er in die ForEach Schleife rein und bleibt dann hier

    VB.NET-Quellcode

    1. wc.DownloadFileAsync(New Uri(String.Format("http://update.webseite.de/{0}", datFile)), datFile)


    einfach stehen. URL hab ich natürlich überprüft und mein Mozilla findet den Link auch (ist ja ein direkt Link zur Datei).

    Nic schrieb:

    da springt er komischerweise nicht rein.
    Dann dürfte doch das auf einen Fehler hindeuten.
    Wie sind denn die Variablen bestückt, dass so was passiert?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Und es wäre sinnvoll Deinen jetzt verwendeten Code mal wieder zu posten , verwende dabei einen Expander um den Text hier nicht noch mehr aufzublähen. Ausserdem wäre es genauso hilfreich uns entweder die richtigen Daten (Web-Adresse ) oder zumindest ein Testszenario zur Verfügung zu stellen, ansonsten können wir es nicht nachstellen.
    Ich habe mal ein Testszenario eingerichtet. Der bisherige Code sieht folgendermaßen aus:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Net
    3. Imports System.Threading
    4. Public Class Main
    5. 'Definierung der Variablen
    6. Public fileNames As String() = {"patch-C", "patch-D", "patch-M", "patch-deDE-3"}
    7. Private t As Thread
    8. Private Event ThreadFinished()
    9. Private waitHandle As New AutoResetEvent(False)
    10. Private WithEvents wc As WebClient
    11. Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    12. 'Vergrößern/Verkleinern des Fensters nicht möglich
    13. MaximizeBox = False
    14. Me.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink
    15. t = New Thread(Sub() checkFiles()) With {.IsBackground = True, .Name = "checkFiles Thread"}
    16. t.Start()
    17. End Sub
    18. Private Sub checkFiles()
    19. Me.Invoke(Sub() pgbDownloadGesamt.Value = 0)
    20. Using wc As New Net.WebClient()
    21. For Each filename As String In fileNames
    22. 'Lade den String der Datei patch-C.txt, patch-D.txt, patch-M.txt und patch-deDE-3.txt von update.lythoria.de/test herunter
    23. Dim webFileSettings As String = wc.DownloadString(String.Format("http://update.lythoria.de/test/{0}.txt", filename))
    24. 'Zieh die lokale Patchversion aus der Registry, falls noch keine existiert wäre diese 0
    25. Dim localFileSettings As String = GetSetting("Lythoria Launcher", "PatchVersionen", filename)
    26. Me.Invoke(Sub() pgbDownloadEinzel.Value = 0)
    27. If localFileSettings < webFileSettings Then
    28. Dim mpqFile As String = String.Format("{0}.MPQ", filename)
    29. wc.DownloadFileAsync(New Uri(String.Format("http://update.lythoria.de/{0}", mpqFile)), mpqFile)
    30. waitHandle.WaitOne()
    31. SaveSetting("Lythoria Launcher", "PatchVersionen", filename, webFileSettings)
    32. End If
    33. Me.Invoke(Sub() pgbDownloadGesamt.Value += 100 / fileNames.Length)
    34. Next
    35. End Using
    36. Me.Invoke(Sub() RaiseEvent ThreadFinished())
    37. End Sub
    38. Private Sub OnWebclientUpdate(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
    39. Me.Invoke(Sub() pgbDownloadEinzel.Value = e.ProgressPercentage)
    40. End Sub
    41. Private Sub OnWebClientFinished(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
    42. Me.Invoke(Sub() pgbDownloadEinzel.Value = 0)
    43. waitHandle.Set()
    44. End Sub
    45. Private Sub OnThreadFinished() Handles Me.ThreadFinished
    46. pgbDownloadEinzel.Value = 0
    47. pgbDownloadGesamt.Value = 0
    48. cmdSpielen.Enabled = True
    49. End Sub
    50. End Class

    Hey,

    Du hast eine etwas verdrehte Vorstellung, wie das im Grunde funktioniert:

    Hier erst mal ein kleines Beispiel.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. For i As Integer = 0 To 4
    4. Dim wC As New Net.WebClient()
    5. Dim downloadID As Integer = i
    6. AddHandler wC.DownloadProgressChanged, AddressOf wc_ProgressChanged
    7. AddHandler wC.DownloadFileCompleted, AddressOf wc_DownloadCompleted
    8. wC.DownloadFileAsync(New Uri("http://download.thinkbroadband.com/50MB.zip"), Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\test" & downloadID.ToString() & ".zip", downloadID)
    9. Next
    10. End Sub
    11. Private Sub wc_ProgressChanged(ByVal sender As Object, ByVal e As Net.DownloadProgressChangedEventArgs)
    12. Dim downloadID As Integer = DirectCast(e.UserState, Integer)
    13. Me.Text = downloadID.ToString()
    14. End Sub
    15. Private Sub wc_DownloadCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
    16. Dim downloadID As Integer = DirectCast(e.UserState, Integer)
    17. MessageBox.Show(downloadID.ToString() & " finished")
    18. End Sub
    19. End Class


    Wenn Du Events dynamisch erzeugst, so brauchst Du keine globale WithEvents-Variable, sondern Du hängst Dich mit dem Schlüsselwort AddHandler eben dynamisch in das Event ein.

    Zweitens: Du musst die Async-Methoden des WebClients benutzen. Die Non-Async-Methoden werfen keine Events.

    Dirttens: Bei Verwendung der Async-Methoden kannst Du auf die Erzeugung eines Threads verzichten. Async läuft in einem anderen Thread!

    Wie Du im Beispiel auch sehen kannst, übernimmt die DownloadFileAsync-Methode in einer ihrer Überladungen einen UserToken. Damit kannst Du die Downloads unterscheiden.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o

    SpaceyX schrieb:

    Du hast eine etwas verdrehte Vorstellung, wie das im Grunde funktioniert:
    Lies ersteinmal die einzelnen Beiträge, Deine Antworten passen leider weder zur Aufgabenstellung noch zum Problem.

    Ansonsten ist der Code in Ordnung, das Problem liegt am Using Statement, was offensichtlich verhindert daß die Events eingetragen werden. Ersetzt man das Using durch ein wc=New WebClient und das End Using durch wc.Dispose(), so funktioniert der Code so wie er soll. Da wir nur 1 Instanz des WebClient benötigen, kann man das auch gleich in der Deklaration erledigen.

    Hier die geänderte Version:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Net
    3. Imports System.Threading
    4. Public Class form1
    5. 'Definierung der Variablen
    6. Public fileNames As String() = {"patch-C", "patch-D", "patch-M", "patch-deDE-3"}
    7. Private t As Thread
    8. Private Event ThreadFinished()
    9. Private waitHandle As New AutoResetEvent(False)
    10. Private WithEvents wc As New WebClient
    11. Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    12. 'Vergrößern/Verkleinern des Fensters nicht möglich
    13. Me.MaximizeBox = False
    14. Me.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink
    15. t = New Thread(Sub() checkFiles()) With {.IsBackground = True, .Name = "checkFiles Thread"}
    16. t.Start()
    17. End Sub
    18. Private Sub checkFiles()
    19. Me.Invoke(Sub() pgbDownloadGesamt.Value = 0)
    20. ' loop filenames
    21. For Each filename As String In fileNames
    22. 'Lade den String der Datei patch-C.txt, patch-D.txt, patch-M.txt und patch-deDE-3.txt von update.lythoria.de/test herunter
    23. Dim webFileSettings As String = wc.DownloadString(String.Format("http://update.lythoria.de/test/{0}.txt", filename))
    24. 'Zieh die lokale Patchversion aus der Registry, falls noch keine existiert wäre diese 0
    25. Dim localFileSettings As String = GetSetting("Lythoria Launcher", "PatchVersionen", filename)
    26. Me.Invoke(Sub() pgbDownloadEinzel.Value = 0)
    27. If localFileSettings < webFileSettings Then
    28. Dim mpqFile As String = String.Format("{0}.MPQ", filename)
    29. wc.DownloadFileAsync(New Uri(String.Format("http://update.lythoria.de/{0}", mpqFile)), mpqFile)
    30. waitHandle.WaitOne()
    31. SaveSetting("Lythoria Launcher", "PatchVersionen", filename, webFileSettings)
    32. End If
    33. Me.Invoke(Sub() pgbDownloadGesamt.Value += 100 \ fileNames.Length)
    34. Next
    35. ' Done
    36. Me.Invoke(Sub() RaiseEvent ThreadFinished())
    37. End Sub
    38. Private Sub OnWebclientUpdate(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
    39. Me.Invoke(Sub() pgbDownloadEinzel.Value = e.ProgressPercentage)
    40. End Sub
    41. Private Sub OnWebClientFinished(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
    42. Me.Invoke(Sub() pgbDownloadEinzel.Value = 0)
    43. waitHandle.Set()
    44. End Sub
    45. Private Sub OnThreadFinished() Handles Me.ThreadFinished
    46. pgbDownloadEinzel.Value = 0
    47. pgbDownloadGesamt.Value = 0
    48. cmdSpielen.Enabled = True
    49. End Sub
    50. End Class


    Überleg Dir mal ob Du den Progressbar-Gesamt nicht wegfallen lassen kannst: z.B. könntest Du ein transparentes Label über die ProgressbarEinzel legen und dort File 1 von 4 anzeigen lassen. Ein customProgressbar mit 2 integrierten Fortschrittsanzeigen wäre natürlich auch cool.
    konzeptionelle Schwächen?
    Scheinbar müssen 4 verschiedene Info-files geladen werden, um zu bestimmen, welche der 4 "Nutzlast-Files" downzuloaden sind.
    Das könnteman in ein Info-File zusammenfassen.
    Dann bin ich sehr unüberzeugt, obs wirklich nötig ist, die Nutzlasten eine nach der anneren zu laden.
    Weil man könnte sie auch parallel laden, in vmtl. einem Drittel der Zeit (kommt auf die Dateien an).
    @EDR
    Zusammenfassung in 1 File: kommt auf das Wartungskonzept des TE an, an der Performance ändert das nichts

    Ein paralleler Download würde dagegen vermutlich einiges an Zeit ersparen: im Beispielcode musste mit einem WaitHandle Synchronität quasi erzwungen werden (s.o.). Aber mehr als maximal eine Halbierung der Ladezeit wird wohl nicht drin sein, da WebServer normalerweise nur höchstens 2 parallele Connections zulassen.

    Das wurde aber schon in den vorhergehenden Beiträgen ansgesprochen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Kangaroo“ ()

    Wenndu echt parallel downloaden willst, sieh Dir mal diesen Thread an.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Kangaroo schrieb:

    Zusammenfassung in 1 File: kommt auf das Wartungskonzept des TE an, an der Performance ändert das nichts
    na, ich glaube fest daran, dass der Download einer Datei mit 4 Zeilen wesentlich performanter ist als 4 Downloads einzeiliger Dateien - annähernd Faktor 4

    Ein paralleler Download würde dagegen vermutlich einiges an Zeit ersparen: im Beispielcode musste mit einem WaitHandle Synchronität quasi erzwungen werden (s.o.). Aber mehr als maximal eine Halbierung der Ladezeit wird wohl nicht drin sein, da WebServer normalerweise nur höchstens 2 parallele Connections zulassen.
    Rods Hinweis deutet eher darauf hin, dass diese Beschränkung im WebClient implementiert ist, nicht im WebServer.
    Und dass man diese Beschränkung einfach ausschalten kann.