【发布时间】:2019-07-20 06:28:39
【问题描述】:
我在获取进度条以显示下载进度时遇到问题。文件正在下载没有问题,但有些东西导致我的进度条没有更新,我不知道为什么。
我尝试在download 和wc_DownloadProgressChanged 方法中手动设置progressBar 值,但它实际改变的唯一地方是Form1_Load 方法。
using System;
using System.Windows.Forms;
using System.Threading;
namespace Launch
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Downloader downloader = new Downloader();
ThreadStart job = new ThreadStart(downloader.download);
Thread thread = new Thread(job);
thread.Start();
}
private void ProgressBar_Click(object sender, EventArgs e)
{
}
public void SetProgress(int val)
{
progressBar.Value = val;
}
public void SetVisible(bool val)
{
progressBar.Visible = val;
}
}
}
using System;
using System.Data;
using System.Net;
using Newtonsoft.Json;
namespace Launch
{
class Downloader
{
public void download()
{
WebClient client = new WebClient();
string url = "https://someurl.com/manifest.json";
string json = client.DownloadString(url);
DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
DataTable dataTable = dataSet.Tables["Required"];
foreach (DataRow row in dataTable.Rows)
{
string remoteUri = row["url"].ToString();
string fileName = row["name"].ToString();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFile(remoteUri, fileName);
Console.WriteLine("Did something with " + remoteUri);
}
}
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
var form = new Form1();
form.SetProgress(e.ProgressPercentage);
}
}
}
有人能解释一下我在这里做错了什么吗?
编辑:
我能够使用DownloadFileAsync 让这个工作大部分时间,但进度条来回跳动,我假设是因为它试图计算每个人的进度文件作为字节被接收,所以我想用 DownloadFile 来解决这个问题。
我现在在使用 DownloadFile 时遇到的问题是,我将它作为一项任务运行,但它跳过了所有文件(不下载任何文件,只是将它们全部打印到控制台超快速)。
这是我目前使用的代码:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
string url = "https://someurl.com/manifest.json";
string json = client.DownloadString(url);
DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
DataTable dataTable = dataSet.Tables["Required"];
foreach (DataRow row in dataTable.Rows)
{
string remoteUri = row["url"].ToString();
string fileName = row["name"].ToString();
Task.Run(() => {
client.DownloadFile(remoteUri, fileName);
});
Console.WriteLine("Did something with " + remoteUri);
}
}
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate {
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
label1.Text = "Downloaded ";
label2.Text = e.BytesReceived.ToString();
label3.Text = e.TotalBytesToReceive.ToString();
progressBar.Value = int.Parse(Math.Truncate(percentage).ToString());
});
}
有什么想法吗?
【问题讨论】:
-
foreach (DataRow row in dataTable.Rows) (...) client.DownloadProgressChanged += client_DownloadProgressChanged;,都给var form = new Form1(); form.SetProgress(e.ProgressPercentage);?我建议使用静态 HttpClient 和 Progress<T> 类。它还会阻止您的代码(在工作时)与自己争夺可用连接。 -
到目前为止,每次 WebClient 实例通知进度时,您都会(从非 UI 线程)创建一个新表单。你最终可能会得到数千个。如果代码可以在这些条件下工作。
-
可能,比以前更糟。一个 WebClient 应该在线程池线程中限制多个同步下载,从
Form.Load事件开始(错误的选择,Load 事件吞噬了异常)。顺便说一句,你为什么还要继续调用DownloadFile,因为这是同步版本,它也不会引发DownloadProgressChanged事件。测试DownloadFileTaskAsync 版本。使用前面提到的Progress<T>类。 SO 上提供了关于这些的代码示例。 -
另外,所有重叠事件(如果生成了这些事件)应该使用单个 ProgressBar 通知进度。如果您发现基于任务的方法难以实现,请选择事件驱动的方法DownloadFileAsync。这将引发
DonwloadProgress和DownloadCompleted事件(您还需要订阅后者)。您必须处理多个 Progress 事件并更新多个 ProgressBar。您还需要处理您创建的每个 WebClient 实例。
标签: c# multithreading progress-bar