2017-05-18 3 views
1

Wie Sie in der Mitte des Codes sehen können, gibt es einen hässlichen Thread-Blockierungscode, der auf den Download der Datei wartet und den Fortschrittsbericht in der Befehlszeile aktiviert. Ich meine, es ist immer noch besser als Thread.Sleep() oder beschäftigt warten, oder? Wie auch immer, ich weiß über Wait/Pulse, aber ich weiß nicht, wie man das hier anwendet.Anhalten des Hauptthreads beim Warten auf DownloadFileAsync() mit Fortschrittsbericht

Ist ein komplettes Refactoring meines Codes besser geeignet für diese einzelne asynchrone Operation die sauberste Lösung? Kann man etwas in der WebClient Klasse überschreiben, um Wait/Pulse Art des Wartens zu verwenden?

Projekt und die Funktion in Frage: Github

Relevante Schnipsel:

static void GetPatch(KeyValuePair<string, string> entry, string part) 
{ 
    string url = entry.Key, 
     fname = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1), 
     path = G.patchPath + "\\" + fname; 
     bool exists = File.Exists(path); 
    Console.Write(fname + " ... "); 
    string message = "local"; 
    if ((exists && GetSHA1(path) != entry.Value) || !exists) 
    { 
     if (exists) File.Delete(path); 
     G.wc.DownloadProgressChanged += Wc_DownloadProgressChanged; 
     G.wc.DownloadFileAsync(new Uri(url), part); 
     while (G.wc.IsBusy) 
     { 
      // There must be a better way 
      new System.Threading.ManualResetEvent(false).WaitOne(200); 
     } 
     G.wc.DownloadProgressChanged -= Wc_DownloadProgressChanged; 
     message = "done"; 
    } 
    if (File.Exists(part)) File.Move(part, path); 
    G.patchFNames.Enqueue(fname); 
    Green(message); 
} 

private static void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
{ 
    int p = e.ProgressPercentage; 
    p = p < 100 ? p : 99; 
    Console.Write("{0:00}%\b\b\b", p); 
} 

Bitte Geduld mit mir, das ist mein erstes Projekt, das ich in C# geschrieben habe, und ich bin ein absolutes Anfänger bei OOP und C#.

+0

Sie müssen auf jeden Fall an dem Code und der Klarheit arbeiten, aber im Allgemeinen denke ich, dass Sie auf einem richtigen Weg sind. Sie benötigen 2 asynchrone Prozesse, einen zum Herunterladen von Dateien und den anderen zum Überwachen des Fortschritts. Der zweite Prozess muss ebenfalls asynchron sein, damit Sie die Benutzeroberfläche nicht blockieren und die Benutzeroberfläche mit dem Dispatcher aktualisieren müssen. – Andrei

+0

Ist es das, wonach Sie suchen? https://alexfeinberg.wordpress.com/2014/09/14/how-to-use-net-webclient-synchronous-and-still-receive-progress-updates/ – MistyK

+0

Wie wäre es mit dem Wechsel zu async \ erwarten? Es gibt 'DownloadFileTaskAsync', das erwartet werden kann, und das wird die meiste Hässlichkeit in diesem Code wegwerfen. – Evk

Antwort

2

ich Lassen Sie den Code aus der URL in meinem Kommentar kopieren:

public void DownloadFile(Uri uri, string desintaion) 
{ 
    using(var wc = new WebClient()) 
    { 
    wc.DownloadProgressChanged += HandleDownloadProgress; 
    wc.DownloadFileCOmpleted += HandleDownloadComplete; 

    var syncObj = new Object(); 
    lock(syncObject) 
    { 
     wc.DownloadFileAsync(sourceUri, destination, syncObject); 
     //This would block the thread until download completes 
     Monitor.Wait(syncObject); 
    } 
    } 

    //Do more stuff after download was complete 
} 

public void HandleDownloadComplete(object sender, AsyncCompletedEventArgs args) 
{ 
    lock(e.UserState) 
    { 
     //releases blocked thread 
     Monitor.Pulse(e.UserState); 
    } 
} 


public void HandleDownloadProgress(object sender, DownloadProgressChangedEventArgs args) 
{ 
    //Process progress updates here 
} 
+0

Ja, perfekt. Ich wusste, dass die UserToken-Überladung der Schlüssel sein wird, aber leider ist MSDN nicht sehr beschreibend/Beispiele fehlen. – user1263513

0

Ihr High-Level-Code wie dieser

public async Task StartFileDownload() 
{ 
    var downloadTask = StartDownload(); 
    var monitoringTask = StartMonitoringProgress(); 

    await Task.WhenAll(downloadTask, monitoringTask); 
} 

Ihre Überwachungsaufgabe all N ms sollte werden überprüft Download-Fortschritt aussehen soll und aktualisieren Sie die Fortschrittsanzeige. Obwohl Sie dies nicht direkt tun können, da Sie nicht auf dem UI-Prozess sind, müssen Sie das UI-Update "versenden".

+1

Auf den ersten Blick deutet Ihr Code darauf hin, dass er 'DownloadFileTaskAsync()' verwendet, das 'Task' zurückgibt, wenn er 'DownloadFileAsync()' verwendet, das [ereignisbasiertes asynchrones Pattern (EAP)] verwendet (https: // msdn. microsoft.com/en-us/library/wewwczdw(v=vs.110).aspx). – Cameron

Verwandte Themen