由於我們需要透過事件來回報處理進度,因此,我們需要客製化一個類別,用來處理這件需求,在這裡,我們需要在新建立的類別,讓他繼承
EventArgs
類別,在這個新的類別,DownloadFileEventArgs,我們新增一個屬性,用來說明處理進度百分比。
另外,對於
Task.Factory.StartNew
,我們有做些調整,在這裡,我們將修飾詞 async
移除了,所以,現在的現在傳入的委派 Lambda 將會是:Task.Factory.StartNew(() => {...}
;由於沒有了 async 修飾詞,所以,在 Task.Factory.StartNew
引數用的委派方法,我們就要進行調整,把原先這個委派方法內有使用到 await 的地方,全部修改成為同步的執行方法;不過,在這裡,你不用擔心,因為我們使用了 Task.Factory.StartNew 啟動一個全新的工作,這個工作會使用 ThreadPool 執行緒集區內的一個執行緒來執行這個工作,所以,也是多工處理的作業。
當要進行回報處理進度事件的時候,我們需要呼叫這個方法:
onProgress(this, new DownloadFileEventArgs() { Percent = percent });
,在第二個引數,我們需要透過 DownloadFileEventArgs 產生的物件,將現在處理進度傳送到訂閱者的綁定方法中。public class DownloadFileEventArgs : EventArgs
{
public int Percent { get; set; }
}
public class DownloadFile
{
public event EventHandler<DownloadFileEventArgs> OnProgress;
//public string Url { get; set; } = "http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/js_api_reference.pdf";
public string Url { get; set; } = "https://www.tutorialspoint.com/csharp/csharp_tutorial.pdf";
public Task Download()
{
var task = Task.Factory.StartNew(() =>
{
int offset = 5120;
int percent = 0;
int currentDonload = 0;
int getBytes;
int lastPercent = -1;
using (var client = new HttpClient())
{
using (var response = client.GetAsync(Url).Result)
{
var total = int.Parse(response.Content.Headers.First(h => h.Key.Equals("Content-Length")).Value.First());
byte[] content = new byte[total+offset];
using (var stream = response.Content.ReadAsStreamAsync().Result)
{
var onProgress = OnProgress;
while ((getBytes = stream.Read(content, currentDonload, offset)) > 0)
{
currentDonload += getBytes;
percent = (int)((1.0 * currentDonload / total) * 100);
if (lastPercent != percent)
{
if (onProgress != null)
{
onProgress(this, new DownloadFileEventArgs() { Percent = percent });
}
lastPercent = percent;
}
}
}
}
}
});
return task;
}
}
現在,讓我們開始進行測試,我們同樣需要訂閱 OnProgress 的事件,不過,您會看到輸出結果卻是不太相同,這並不是我們使用事件的方式,你可以知道發生了甚麼問題以及差異在哪裡?
static async Task Main(string[] args)
{
DownloadFile downloadFile = new DownloadFile();
downloadFile.OnProgress += DownloadStatus;
Console.WriteLine($"開始進行非同步檔案檔案下載");
await downloadFile.Download();
Console.WriteLine($"{Environment.NewLine}Press any key to Exist...");
Console.ReadKey();
}
private static void DownloadStatus(object sender, DownloadFileEventArgs e)
{
if (e.Percent % 10 == 0)
{
Console.Write($" {e.Percent}% ");
}
else
{
Console.Write($".");
}
}
底下是執行結果
開始進行非同步檔案檔案下載
0% ......... 10% ......... 20% ......... 30% ......... 40% ......... 50% ......... 60% ......... 70% ......... 80% ......... 90% ......... 100%
Press any key to Exist...
C# : 網路下載檔案之下載進度委派方法
練習中,我們使用的委派型別,來做為通知使用者最新的下載進度,在這裡,我們將會使用 C# 的事件 Event,來做出相同效果的程式碼。