C# DownloadProgressChangedEventArgs || Falscher Status?
lima-city → Forum → Programmiersprachen → Programmieren mit .NET & Mono
apartment
aufrufen
ausgabe
ausgeben
code
darstellung
ereignis
ergebnis
erzeugen
exklusiver zugriff
konsole
methode
objekt
pool
problem
sender
string
system
url
zugreifen
-
Habe mir nur mal nebenbei eine kleine Consolenanwendung gebastelt, die den Downloadstatus wärend eines Downloads anzeigen soll.
Die Ergebnisse sind aber etwas seltsam.
Hier der Programmcode:
static void Main(string[] args) { WebClient client = new WebClient(); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted); client.DownloadFileAsync(new Uri("DateiZumDownloaden.zip"), "Dateipfad.zip"); } private static void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { Console.WriteLine(e.BytesReceived.ToString() + " / " + e.TotalBytesToReceive.ToString() + " (" + e.ProgressPercentage.ToString() + " %)"); } private static void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { Console.WriteLine("Done!"); }
Und das ist das Ergebnis (gekürzt):
2141656 / 4355399 (49 %)
2175236 / 4355399 (49 %)
2188376 / 4355399 (50 %)
2264296 / 4355399 (51 %)
2351896 / 4355399 (53 %)
2375256 / 4355399 (54 %)
2426356 / 4355399 (55 %)
2468696 / 4355399 (56 %)
2522716 / 4355399 (57 %)
2527096 / 4355399 (58 %)
1147396 / 4355399 (26 %)
1150316 / 4355399 (26 %)
2561972 / 4355399 (58 %)
2655412 / 4355399 (60 %)
2696292 / 4355399 (61 %)
2743012 / 4355399 (62 %)
2785352 / 4355399 (63 %)
2789732 / 4355399 (64 %)
2842292 / 4355399 (65 %)
1147396 / 4355399 (26 %)
2915292 / 4355399 (66 %)
2935732 / 4355399 (67 %)
3040852 / 4355399 (69 %)
3091872 / 4355399 (70 %)
3122532 / 4355399 (71 %)
3177848 / 4355399 (72 %)
3196828 / 4355399 (73 %)
1147396 / 4355399 (26 %)
3199748 / 4355399 (73 %)
2532936 / 4355399 (58 %)
3215644 / 4355399 (73 %)
3287020 / 4355399 (75 %)
2535856 / 4355399 (58 %)
3342336 / 4355399 (76 %)
3407872 / 4355399 (78 %)
3295780 / 4355399 (75 %)
3523048 / 4355399 (80 %)
3208508 / 4355399 (73 %)
3546244 / 4355399 (81 %)
1147396 / 4355399 (26 %)
1147396 / 4355399 (26 %)
3549164 / 4355399 (81 %)
3552084 / 4355399 (81 %)
3473408 / 4355399 (79 %)
3560844 / 4355399 (81 %)
3572524 / 4355399 (82 %)
3556464 / 4355399 (81 %)
3576904 / 4355399 (82 %)
3584204 / 4355399 (82 %)
3525968 / 4355399 (80 %)
3588584 / 4355399 (82 %)
3604480 / 4355399 (82 %)
3587124 / 4355399 (82 %)
3614700 / 4355399 (82 %)
3619080 / 4355399 (83 %)
3639520 / 4355399 (83 %)
3642440 / 4355399 (83 %)
3581284 / 4355399 (82 %)
3657040 / 4355399 (83 %)
3681696 / 4355399 (84 %)
3735552 / 4355399 (85 %)
3744312 / 4355399 (85 %)
3747232 / 4355399 (86 %)
3750152 / 4355399 (86 %)
3753072 / 4355399 (86 %)
3757452 / 4355399 (86 %)
1147396 / 4355399 (26 %)
3761832 / 4355399 (86 %)
3764752 / 4355399 (86 %)
3767672 / 4355399 (86 %)
1147396 / 4355399 (26 %)
1147396 / 4355399 (26 %)
3770592 / 4355399 (86 %)
3774972 / 4355399 (86 %)
3801088 / 4355399 (87 %)
3834668 / 4355399 (88 %)
3652660 / 4355399 (83 %)
3863868 / 4355399 (88 %)
3948220 / 4355399 (90 %)
1147396 / 4355399 (26 %)
3958440 / 4355399 (90 %)
3961360 / 4355399 (90 %)
3997696 / 4355399 (91 %)
4003536 / 4355399 (91 %)
4077832 / 4355399 (93 %)
3868084 / 4355399 (88 %)
3610320 / 4355399 (82 %)
4089512 / 4355399 (93 %)
4092432 / 4355399 (93 %)
4095352 / 4355399 (94 %)
4143368 / 4355399 (95 %)
4147748 / 4355399 (95 %)
4194304 / 4355399 (96 %)
4201604 / 4355399 (96 %)
4226424 / 4355399 (97 %)
4239564 / 4355399 (97 %)
1147396 / 4355399 (26 %)
4085132 / 4355399 (93 %)
4259840 / 4355399 (97 %)
4299260 / 4355399 (98 %)
1147396 / 4355399 (26 %)
1147396 / 4355399 (26 %)
4305100 / 4355399 (98 %)
4310940 / 4355399 (98 %)
1147396 / 4355399 (26 %)
4313860 / 4355399 (99 %)
4355399 / 4355399 (100 %)
4355399 / 4355399 (100 %)
1147396 / 4355399 (26 %)
4241024 / 4355399 (97 %)
Done!
4080752 / 4355399 (93 %)
Weiß jemand, warum das Ergebnis der Ausgabe nicht geordnet von 0 bis 100 Prozent zählt und sogar noch nach Auslösen des DownloadFileCompleted Events eine Statusanzeige vom DownloadProgressChanged Event kommt?
Das stimmt doch was nicht.
Ich versuche das später auf eine progressBar zu übertragen, aber bei so einer Ausgabe würde die wohl nur sinnlos durch die Gegend hüpfen. o.O -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Hallo adelwoehrer,
ich konnte das Problem bei mir leider nicht nachstellen. Aber evtl. hängt es mit dem Threading-Model zusammen.
Schau mal, ob das Problem weg ist, wenn Du die Main() so annotierst:
[STAThread] static void Main(string[] args) { ... }
-
Das Problem besteht leider auch weiterhin.
Rein aus Interesse....was würde [STAThread] normalerweise bewirken?
Ich kann nicht so ganz nachvollziehen, woher das Problem rührt.
Allmählich fange ich sogar an zu glauben, es handelt sich um ein Anzeigeproblem der Konsole.
Wenn ich die Ergebnisse nämlich nicht in der Konsole ausgeben lasse, sondern in einer Textdatei logge, stimmt die Reihenfolge. o.O -
Hallo adelwoehrer,
genau wusste ich es auch nicht. Ich habe nur mal gelesen, dass man GUI-Thread immer mit [STAThread] erzeugen sollte und weil Du Sachen aus System.ComponentModel verwendest dachte ich, dass es evtl. was ändert.
Ich habe aber etwas herumgeschaut und kann es jetzt erklären.
Das Threading-Modell beschreibt, wie Thread auf COM-Objekte (OLE, DCOM, COM, COM+, ActiveX,...) zugreifen können.
STA bedeutet Single Threaded Apartment. D.h. Wenn ein Thread ein COM-Objekt erzeugt, dann kann nur der erzeugende Thread Methoden des Objektes aufrufen. Wenn ein anderer Thread eine Methode des Objektes aufrufen will, dann geht das nur über eine Delegate, der mittels Invoke() im erzeugenden Thread ausgeführt wird. Dazu muss der erzeugende Thread aber über eine MessagePump verfügen.
MTA bedeutet Mutli-Threaded Apartment. Hierbei kann jeder Thread die Methoden eines COM-Objektes direkt aufrufen. Allerdings ist nicht jedes COM-Objekt thread-safe, weshalb man das besser vermeiden sollte. Ob die .NET-Runtime das Erzeugen von unsichern Objekten in MTA-Threads verhindert kann ich auch nicht sagen. Möglich wäre es wohl, da in der Registry angegeben werden kann, ob ein COM-Objekt mit MTA klar kommt.
Zum ursprünglichen Problem:
Auch da habe ich noch etwas herumgesucht, um herauszufinden, wie die Abarbeitung von Events/Delegates eigentlich funktioniert. Ein offizielles Dokument zum Thema habe ich nicht gefunden aber aus diversen Foreneinträgen kann ich es mir doch zusammenreimen.
1. Synchrones Ereignis:
Wenn ein Thread ein Event durch einfaches aufrufen auslöst, dann werden die Delegates im auslösenden Thread verarbeitet.
2. Asynchrones Ereignis:
Wenn ein Thread ein Event asynchron auslöst, dann werden die Delegates durch Threads aus einem Thread-Pool ausgeführt.
Der Thread-Pool wird vom Dispatcher verwaltet.
In der Konsole werden die einzelnen Ereignisse also auf Threads aus dem Thread-Pool verteilt. Wahrscheinlich werden die Ereignisse vom WebClient etwas schneller ausgelöst, als sie von den Dispatcher-Threads auf der Konsole ausgeben werden können (exklusiver Zugriff eines Threads beim Schreiben). Daher werden einige Threads zurückgestellt, bis sie Zugriff auf die Konsole bekommen. Das aufwecken der Threads ist aber nicht chronologisch sondern eher zufällig, weshalb es sein kann, dass ein Ereignis, das sehr früh ausgelöst wurde erst gegen Ende zum Schreiben kommt.
Noch eine Vorwarnung:
Wenn Du in einem Ereignis-Handler der durch einen anderen Thread ausgelöst wird ein GUI-Control verändern willst (z.B. ProgressBar), dann musst Du diese Aufgabe im GUI-Thread ausführen, da GUI-Controls sich nur aus dem erzeugenden Thread heraus manipulieren lassen.
Aber dazu gibt es wenigstens einen Artikel:
http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.80%29.aspx
Beitrag zuletzt geändert: 14.6.2012 22:02:17 von darkpandemic -
Hmm, das klingt logisch.
Heißt konkret einfach, das Event wird zu oft ausgelöst, als dass die Konsole mit der Darstellung nachkommt.
Deshalb werden einige Events in eine Warteschlange gereiht, die aber nicht der Reihe nach abgearbeitet wird.
Heißt im Prinzip, es funktioniert alles, ich sollte nur den nicht jeden Byte ausgeben wollen. ^^
Was die Thread-Übergreifenden Dinge angeht.
Derzeit verwende ich da den Befehl "CheckForIllegalCrossThreadCalls = false;" direkt bei Programmstart.
Das schaltet die Überprüfung ab....ist nicht Thread-Save, ich weiß, hatte aber nie Probleme damit. =)
So ist es auch möglich, GUI Elemente aus einem anderen Thread heraus zu bearbeiten.
Beitrag zuletzt geändert: 14.6.2012 22:50:00 von adelwoehrer -
Man kann auch einfach check ob 'InvokeRequired' true ist und dann einfach das ganze per Invoke ausführen.
-
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage