Autor |
Beitrag |
Findus
      
Beiträge: 26
|
Verfasst: So 21.12.08 02:32
Hallo zusammen ..
Ich bin ein Blutiger Anfänger in sachen Programmieren und hätte ein paar Fragen die mir auch Google und Co. nach Stundenlanger Suche
nicht beantworten konnten. Mir fehlt als Newcomer einfach noch das Verständnis für viele Sachen.
In meinem Programm lade ich mir Daten auf meinem Rechner mit denen ich dann wieder arbeiten kann. Dazu lese ich ein csv-file ein.
Nun beim Download wird mir in einem neuen Form eine progressbar angezeigt. Der Fortschritt des Downloads bringt die GUI wie nicht anderest zu erwarten zum erliegen bzw. blockiert sie.
Hier erst mal der Code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| private void button1_Click(object sender, EventArgs e) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://www.URL2GO.de/xxx.csv"); request.Method = "GET"; HttpWebResponse hwrs = (HttpWebResponse)request.GetResponse(); BinaryReader br = new BinaryReader(hwrs.GetResponseStream()); FileStream fs = new FileStream(@"xxx.csv", FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs);
progressBar1.Minimum = 0; progressBar1.Maximum = (int)hwrs.ContentLength; progressBar1.Step = 1; this.Text = String.Format("Download {0} bytes", hwrs.ContentLength);
try { while (true) { progressBar1.PerformStep(); bw.Write(br.ReadByte()); } } catch (Exception) { bw.Close(); fs.Close(); } Application.Restart(); } |
Im Anhang ist das Form zu sehen wie das ganze aussieht.
So nun meine Frage:
1. Wie könnte ich es anstellen das die GUI auf einfachste Weise nicht mehr blockiert wird. Themen wie Threading und Backgroundworker habe ich gelesen aber leider nicht verstanden
Evtl. hat ja jemand ein ganz simples Beispiel für mich.
Was erwarte ich NICHT:
Ich erwarte keine Fertige Lösung, auch wenn das der einfachste Weg ist.  Nein, ich will das schon auch verstehen.
So, ich hoffe ich habe nicht gleich gegen die Regeln verstoßen und zumindest richtig gepostet.
Gruß Findus
Moderiert von Christian S.: C#-Tags hinzugefügt
Moderiert von Christian S.: Topic aus IO, XML und Registry verschoben am So 21.12.2008 um 01:37
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
Einloggen, um Attachments anzusehen!
Zuletzt bearbeitet von Findus am Do 25.12.08 18:05, insgesamt 1-mal bearbeitet
|
|
PerryRhodan
      
Beiträge: 34
C# (VS 2005 + 2008), .NET 2.0 + 3.5 (inkl. WPF, WCF)
|
Verfasst: So 21.12.08 10:18
Hallo Findus,
auf einfachste Weise würden Dir die Aufrufe
C#-Quelltext 1: 2:
| progressBar1.Invalidate(); progressBar1.Update(); |
schon weiterhelfen.
Deine Programmlogik arbeitet im gleichen Thread wie die GUI. Standardmäßig wird kein neues Zeichnen der Controls erzwungen sondern nur "vermerkt", dass das Control bei nächster Gelegenheit neu gezeichnet werden soll. Dies passiert, wenn Zeit dafür da ist. Da Deine Logik aber alle dem Thread zugeteilte Rechenzeit nutzt, wird die GUI nicht neu gezeichnet.
Durch den Invalidate-Aufruf erzwingst Du, dass das gesamte Control beim nächsten Zeichnen neu gezeichnet werden muss. Durch den Update-Aufruf erzwingst Du dann das Zeichnen selbst.
Grüße
PerryRhodan
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: So 21.12.08 11:36
Der "Unsterbliche" hat recht: mit längeren Arbeiten wird die GUI "immer" blockiert.
Ich empfehle, dass Du Dir den BackgroundWorker nochmals vornimmst. Das einführende Beispiel in der SDK-Doku/MSDN ist meiner Ansicht nach sehr gut geeignet.
Gruß Jürgen
|
|
Findus 
      
Beiträge: 26
|
Verfasst: So 21.12.08 12:57
Hallo Ihr beiden ..
Erst mal thanks für die Info. Ich hab die progressbar Parameter mal mit eingebaut. Leider bringt das nicht den gewünschten Erfolg. Das liegt aber sicher an meinem newbie Programmierstiel
Mit dem backgroundworker steh ich auf Kriegsfuß. Ich bekomme das einfach nicht gebacken. Ich glaube da muss ein Workshop her .. lol
Einstweilen vielen Dank !
Findus
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: So 21.12.08 13:27
Tja, wenn Du Deine Versuche mit dem BackgroundWorker zitieren würdest, könnten wir auch dazu helfen.
Wenn es nur darum geht, eine (nicht zu große) Datei zu laden und zu speichern, dann könntest Du auch WebClient.DownloadFile-Methode verwenden. Ich benutze das regelmäßig und vermisse die Fortschrittsanzeige bei 50 kB pro Datei überhaupt nicht.
Jürgen
|
|
Findus 
      
Beiträge: 26
|
Verfasst: So 21.12.08 14:30
JüTho hat folgendes geschrieben : | Tja, wenn Du Deine Versuche mit dem BackgroundWorker zitieren würdest, könnten wir auch dazu helfen.
Wenn es nur darum geht, eine (nicht zu große) Datei zu laden und zu speichern, dann könntest Du auch WebClient.DownloadFile-Methode verwenden. Ich benutze das regelmäßig und vermisse die Fortschrittsanzeige bei 50 kB pro Datei überhaupt nicht.
Jürgen |
Erst mal wieder Danke Jürgen für die Antwort. Zuerst, ja ich habe auch nur ein File das nur ca. 100 kB groß ist, aber finde es schön wenn sich was bewegt da ich nur eine ISDN Leitung habe und wohl die nächsten Jahre nichts anderes bekomme. Ich werde mich nun nochmal mit dem BackgroundWorker beschäftigen und dann meine Probleme schlildern.
Thanks Findus
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
|
|
Findus 
      
Beiträge: 26
|
Verfasst: So 21.12.08 14:52
Hier also meine Erfahrungen/Fehler und Dummheiten die ich so mache.
Also, erst mal ich arbeite mit MS Visual Studio 2008 und ziehe mir den backgroundWorker aus der Toolbar auf mein DownloadForm. Nun setze ich die Parameter WorkerReportsProgress und WorkerSupportsCancellation des Workers auf True.
Der Quellcode schaut nun so aus.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; using System.IO; using System.Net;
namespace XYZ { public partial class DownloadForm : Form { public DownloadForm() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(); this.button1.Enabled = false;
while (this.backgroundWorker1.IsBusy) { Application.DoEvents(); }
this.button1.Enabled = true; }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://URL2GO/xyz.csv"); request.Method = "GET"; HttpWebResponse hwrs = (HttpWebResponse)request.GetResponse(); BinaryReader br = new BinaryReader(hwrs.GetResponseStream()); FileStream fs = new FileStream(@"xyz.csv", FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs);
progressBar1.Invalidate(); progressBar1.Minimum = 0; progressBar1.Maximum = (int)hwrs.ContentLength; progressBar1.Step = 1;
this.Text = String.Format("Download {0} bytes", hwrs.ContentLength);
try { while (true) { progressBar1.PerformStep(); progressBar1.Update(); bw.Write(br.ReadByte()); } } catch (Exception) { bw.Close(); fs.Close(); } Application.Restart(); }
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error == null) { MessageBox.Show("Complete"); } else { MessageBox.Show( "Failed", "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void button2_Click(object sender, EventArgs e) { Close(); } } } |
Nur passieren tut nichts  Nach einem klick auf OK tut sich garnichts.
Vermutlich ein ganz ganz großer Denkfehler meinerseits. Newbie halt.
Gruß Findus
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Mo 22.12.08 19:07
Hallo,
sorry, bisher hatte ich keine Zeit, Deinen Code zu untersuchen.
Du machst vor allem folgenden Fehler - zitiert aus der SDK-Doku/MSDN:
Zitat: | BackgroundWorker-Klasse Hinweis
Im DoWork-Ereignishandler dürfen keine Benutzeroberflächenobjekte bearbeitet werden. Verwenden Sie stattdessen zum Kommunizieren mit der Benutzeroberfläche das ProgressChanged-Ereignis und das RunWorkerCompleted-Ereignis. |
Du rufst dort mehrfach die ProgressBar und Textbox auf, das ist falsch. Es geht ja gerade darum, dass die GUI und die Hintergrundarbeit getrennt werden.
Diese Zeile aus dem Beispiel der Doku ist besonders wichtig:
C#-Quelltext 1:
| backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged; |
Die ProgressBar wird eigentlich nur in der backgroundWorker1_ProgressChanged-Methode benutzt.
Noch ein paar schnelle Bemerkungen:
* DoWork selbst macht fast nichts, sondern die Arbeit wird in eine getrennte Methode ReadWrite (im Beispiel ComputeFibonacci) ausgelagert.
* Die IsBusy-Schleife kann entfallen.
* button1.Enabled = true gehört in das Completed-Ereignis.
Bitte versuchs noch einmal. Jürgen
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Di 23.12.08 01:29
Hallo Jürgen,
also ich hab mich nochmal an die Arbeit gemacht. Bislang leider ohne Erfolg  Ich denke ich bin auch dem Richtigen weg, aber leider fehlt noch der Erfolg. Hier mal mein derzeitiger Code der allerdings noch nicht vollständig ist. Es scheitert noch an der Fehlerabfrage bei Cancel.
Die Arbeit macht er natürlich auch noch nicht.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Net; using System.Reflection;
namespace XYL { public partial class DownloadForm : Form { public DownloadForm() { InitializeComponent(); InitializeBackgoundWorker(); }
private void InitializeBackgoundWorker() { backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler( backgroundWorker1_RunWorkerCompleted); backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler( backgroundWorker1_ProgressChanged); }
private void okButton_Click(object sender, EventArgs e) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://URL2GO/xyl.csv"); request.Method = "GET"; HttpWebResponse hwrs = (HttpWebResponse)request.GetResponse(); BinaryReader br = new BinaryReader(hwrs.GetResponseStream()); FileStream fs = new FileStream(@"xyl.csv", FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs);
this.okButton.Enabled = false;
this.cancelButton.Enabled = true;
progressBar1.Minimum = 0; progressBar1.Maximum = (int)hwrs.ContentLength; progressBar1.Step = 1;
this.Text = String.Format("Download {0} bytes", hwrs.ContentLength);
backgroundWorker1.RunWorkerAsync(); }
private void cancelButton_Click(object sender, EventArgs e) { this.backgroundWorker1.CancelAsync();
cancelButton.Enabled = false; }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker;
try { while (true) { bw.Write(br.ReadByte()); } } catch (Exception) { bw.Close(); fs.Close(); }
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { MessageBox.Show(e.Error.Message); } else if (e.Cancelled) { resultLabel.Text = "Canceled"; } else { resultLabel.Text = "???"; }
okButton.Enabled = true;
cancelButton.Enabled = false;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage; }
} } |
Was natürlich auch nicht geht ist das schreiben der Datei in DoWork da ich die Variablen ja nicht aus der Methode okButton_Click übernehmen kann. Was die Anzeige der progressbar angeht steht dann wieder auf einem anderen Blatt. Vielleicht könnte man nochmal Hilfestellung geben, Danke ..
Ich hoffe das nun zumindest die Ansätze richtig sind.
Gruß Findus
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Di 23.12.08 17:20
So, ich habe das Projekt jetzt selbst bearbeitet. Folgende Änderungen sind erforderlich bzw. sinnvoll.
Der BackgroundWorker ist in den Tools enthalten. Er kann also im Designer vorbereitet werden; dann ist die Methode InitializeBackgoundWorker() in der Designer.cs enthalten.
Der entscheidende Fehler ist jetzt, dass der Download-Aufruf im ButtonClick enthalten ist. Das gehört alles in den Arbeitsablauf des BackgroundWorker, wie ich oben schrieb:
JüTho hat folgendes geschrieben : | Es geht ja gerade darum, dass die GUI und die Hintergrundarbeit getrennt werden. |
ButtonClick enthält nur noch solche Maßnahmen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| void OkButtonClick(object sender, EventArgs e) { okButton.Enabled = false; cancelButton.Enabled = true;
progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Value = 0; progressBar1.Step = 1;
backgroundWorker1.RunWorkerAsync();
while (backgroundWorker1.IsBusy) { Application.DoEvents(); } } |
So kann das DoWork aussehen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| void BackgroundWorker1DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.Text); request.Method = "GET"; HttpWebResponse hwrs = (HttpWebResponse)request.GetResponse(); BinaryReader br = new BinaryReader(hwrs.GetResponseStream()); FileStream fs = new FileStream(Path.Combine(Application.CommonAppDataPath, "temp.csv"), FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs); long summary = hwrs.ContentLength; int section = (int)summary / 100; int progress = 0; int counter = 0; try { while (true) { bw.Write(br.ReadByte()); counter++; if (counter >= section) { worker.ReportProgress(++progress, summary); counter = 0; } } } catch { } finally { bw.Close(); br.Close(); fs.Close(); hwrs.Close(); } } |
Entscheidend ist, dass die Arbeit in DoWork enthalten ist und ReportProgress bewusst aufgerufen wird. Dazu müssen die Bytes mitgezählt werden. (Zu einer Alternative, die mir eigentlich besser gefällt, schreibe ich unten noch etwas. Hier geht es mir erst um eine funktionierende Lösung.)
cancelButton_Click und backgroundWorker1_RunWorkerCompleted sind in Ordnung.
backgroundWorker1_ProgressChanged habe ich erweitert, damit die Gesamtzahl der Bytes angezeigt werden kann (siehe oben den Parameter summary):
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| void BackgroundWorker1ProgressChanged(object sender, ProgressChangedEventArgs e) { if (progressBar1.Value == 0) { Text = String.Format("Download {0} bytes", (long)e.UserState); } progressBar1.Value = e.ProgressPercentage; } |
Weitere Hinweise: Ich hatte ja schon bezweifelt, dass bei einem solchen Download eine ProgressBar sinnvoll ist. Der Arbeitsablauf hat dies bestätigt: Durch GetResponse wird die Datei abgeholt und im Arbeitsspeicher zwischengespeichert; dies erfolgt ohne Anzeige des Fortschritts. Erst beim Abspeichern ist die Anzeige möglich. (Wie es z.B. im Browser gemacht wird, weiß ich nicht; ich kenne nur die wichtigsten Zusammenhänge mit einem WebClient.)
Das Byte-weise Abspeichern ist auch nicht sehr sinnvoll. Besser ist ein Umspeichern in Blöcken, etwa so:
C#-Quelltext 1: 2: 3: 4: 5:
| while (true) { bw.Write(br.ReadBytes(section)); worker.ReportProgress(++progress, summary); } |
Aber entgegen der Beschreibung von ReadBytes wird der letzte (unvollständige) Block nicht gelesen (und ich hatte keine Lust, das auch noch zu prüfen).
Ich hoffe, dass Dir mit diesem Beispiel und den Erläuterungen der Zusammenhang klarer wird.
Viel Erfolg und Frohe Weihnachten! Jürgen
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Di 23.12.08 19:15
Hallo Jürgen,
erst mal vielen vielen Dank für Deine ausführliche Hilfe. So wurde mir Schritt für Schritt klarer um was es geht und auf was es ankommt.
Das ganze Funktioniert nun erst mal. Was mich allerdings wundert ist das die Progressbar 2 mal durchlaufen wird !? Von der Zeit her könnte es auch
fast sein das das File 2 mal geladen wird. Leider fällt mir keine Lösung ein um dies zu testen.
Was noch nicht geht ist das Cancel. Ein Abbruch ist nicht möglich. Aber das bekomme ich denke ich schon gebacken.
Gruß Findus
Moderiert von Christian S.: Überflüssige Zeilenumbrüche entfernt
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Di 23.12.08 19:28
Findus hat folgendes geschrieben : | Was mich allerdings wundert ist das die Progressbar 2 mal durchlaufen wird !? Von der Zeit her könnte es auch fast sein das das File 2 mal geladen wird. Leider fällt mir keine Lösung ein um dies zu testen. |
Dann kontrolliere noch einmal Deinen Code. Vielleicht wird das Einlesen noch in ButtonClick aufgerufen...
Findus hat folgendes geschrieben : | Was noch nicht geht ist das Cancel. Ein Abbruch ist nicht möglich. Aber das bekomme ich denke ich schon gebacken. |
Ach, das hatte ich vergessen zu testen. Ich hatte es mit eigenem Code verglichen, und mir war nichts aufgefallen. Allerdings musst Du bedenken, dass Windows etwas Zeit braucht, um auf solch eine Anweisung zu reagieren; vielleicht ist die Datei schneller gespeichert...
Gruß Jürgen
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Di 23.12.08 20:03
Hallo nochmal Jürgen ..
Ich habe nun den Code nun nochmal geprüft auf doppelte Aufrufe. Also mir fällt diesbezüglich nichts auf, was nach nichts heisen will.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Net; using System.Reflection;
namespace XYZ { public partial class DownloadForm : Form { public DownloadForm() { InitializeComponent(); InitializeBackgoundWorker(); }
private void InitializeBackgoundWorker() { backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); }
private void okButton_Click(object sender, EventArgs e) { okButton.Enabled = false; cancelButton.Enabled = true;
progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Value = 0; progressBar1.Step = 1;
backgroundWorker1.RunWorkerAsync();
while (backgroundWorker1.IsBusy) { Application.DoEvents(); } }
private void cancelButton_Click(object sender, EventArgs e) { this.backgroundWorker1.CancelAsync(); cancelButton.Enabled = false; }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"URL2GO/temp.csv"); request.Method = "GET"; HttpWebResponse hwrs = (HttpWebResponse)request.GetResponse(); BinaryReader br = new BinaryReader(hwrs.GetResponseStream()); FileStream fs = new FileStream(@"temp.csv", FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs);
long summary = hwrs.ContentLength; int section = (int)summary / 100; int progress = 0; int counter = 0;
try { while (true) { bw.Write(br.ReadByte()); counter++; if (counter >= section) { worker.ReportProgress(++progress, summary); counter = 0; } } } catch { } finally { bw.Close(); br.Close(); fs.Close(); hwrs.Close(); } }
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { MessageBox.Show(e.Error.Message); } else if (e.Cancelled) { this.Text = "Canceled"; } else { Close(); }
okButton.Enabled = true;
cancelButton.Enabled = false; }
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { if (progressBar1.Value == 0) { Text = String.Format("Download {0} bytes", (long)e.UserState); } progressBar1.Value = e.ProgressPercentage; }
} } |
Vielleicht kann man ja nochmal einen Blick drauf werfen. Wie gesagt die progressbar läuft zwei mal durch und erweckt den Eindruck das die Datei zwei mal geladen wird.
Gruß Findus
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Mi 24.12.08 00:58
Hallo nochmal @all ..
Ich hab nun nochmal ein paar Tests durchlaufen. Er schreibt das File definitiv zwei mal. Getestet hab ich das einfach indem ich das FileMode.Create durch ein FileMode.Append ersetzt habe. Also, File vorher gelöscht und nochmal auf Download geklick. Resultat ist eine doppelte Dateigröße
Gruß Findus
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Mi 24.12.08 11:59
Hallo,
tut mir leid, ich sehe auch nichts. Das einzige, was mir etwas "kritisch" vorkommt, ist das Close() in RunWorkerCompleted. Aber das dürfte eigentlich so etwas nicht auslösen: Es ist Bestandteil des Formulars (des GUI-Threads) und wird ausgelöst, wenn der BackgroundWorker wirklich abgeschlossen ist; was sollte das also Schlimmes verursachen?
Vielleicht hat einer der anderen NET-Kenner eine Idee?!
Gruß und Frohe Weihnachten! Jürgen
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 24.12.08 12:16
Ich glaube, es liegt an der Methode, wie hier entschieden wird, ob ein Fortschritt "gemeldet" wird.
Nehmen wir an, summary ist 190. Dann ist section = (int) summary / 100 nur 1. Das heißt bei jedem Durchlauf der while-Schleife wäre counter >= section. Wenn aber 100mal ein Fortschritt vermeldet wurde (also eigentlich 100% erreicht sein müssten), dann sind noch 90 Bytes zu lesen. Und es wird auch noch 90mal ein Fortschritt vermeldet.
Wenn nun noch (Vermutung!) ReportProgress bei einem Fortschrittswert von > 100 wieder von vorne anfängt, würde die Prpgressbar mehr als einmal durchlaufen.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Mi 24.12.08 12:55
Hallo Christian S ..
Danke für die Info. Das selbe hab ich allerdings auch schon vermutet und die while-Schleife mal raus genommen. Selber effekt. Nur das man halt nichts mehr sieht
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| |
Schöne Weihnachten
Findus
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 24.12.08 13:05
Dann versuch mal, sowohl den BinaryReader als auch den BinaryWriter wegzulassen. Die brauchst Du eh nicht, weil die Streams eine ReadByte bzw. WriteByte Methode haben.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Findus 
      
Beiträge: 26
|
Verfasst: Mi 24.12.08 14:56
Christian S. hat folgendes geschrieben : | Dann versuch mal, sowohl den BinaryReader als auch den BinaryWriter wegzulassen. Die brauchst Du eh nicht, weil die Streams eine ReadByte bzw. WriteByte Methode haben. |
Hallo Christian. Nun muss sich natürlich wieder der Anfänger in mir outen. Ich bekomme das ohne BR und BW nicht gebacken
Gruß und Frohes Fest
Findus
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 24.12.08 15:18
Den Writer lässt Du einfach weg und da, wo Du im Moment noch bw.Write aufrufst, rufst Du stattdessen fs.WriteByte auf.
Den Reader lässt Du auch weg, und schnappst Dir stattdessen direkt den RepsonseStream (Stream resp = hwrs.GetResponseStream();) Der hat dann die Methode ReadByte.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|