【发布时间】:2017-03-08 09:49:02
【问题描述】:
我有一些文件要从 ftp 服务器下载。我想要实现的是:
- 有一个
SplitContainer,ListView在MainForm的一个面板中。 - 我想要下载文件列表,为
ListView中的每个文件创建一个ProgressBar和一个Label - 在
ProgressChanged事件中,我想在ProgressBar上显示文件的当前进度,在Label上显示当前下载速度
这是我的代码的最新版本:
internal async Task GetFiles(IEnumerable<string> urlList)
{
string dir = Environment.CurrentDirectory + "\\updates";
Directory.CreateDirectory(dir);
var tasks = new List<Task>();
foreach (var url in urlList)
tasks.Add(DownloadFile(url, dir));
await Task.WhenAll(tasks);
}
internal async Task DownloadFile(string url, string dir)
{
string filename = Helper.GetFilenameFromUrl(url);
ProgressBar pb = CreateFileDownloadBar();
Label lb = CreateFileDownloadLabel();
Stopwatch sw = new Stopwatch();
Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls.Add(pb));
Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls.Add(lb));
using (var client = new WebClient())
{
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler((sender, e) => ProgressChanged(sender, e, sw, pb, lb));
client.DownloadFileCompleted += new AsyncCompletedEventHandler((sender, e) => Completed(sender, e, sw));
Helper.CrossThreadInvoke(_sender, () => _sender.lblFileDownload.Text = Helper.GetFilenameFromUrl(url));
await client.DownloadFileTaskAsync(url, string.Concat(dir, "\\", filename));
}
}
private Label CreateFileDownloadLabel()
{
Label lb = new Label()
{
Location = new System.Drawing.Point(_sender.offset - 180, 5 + offset)
};
return lb;
}
private ProgressBar CreateFileDownloadBar()
{
ProgressBar pb = new ProgressBar()
{
Location = new System.Drawing.Point(5, 5 + offset),
Size = new System.Drawing.Size(200, 20)
};
offset += pb.Height + 5;
return pb;
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e, Stopwatch sw, ProgressBar pb, Label lb)
{
pb.Value = e.ProgressPercentage;
lb.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
}
但是,pb 和 lb 在这种情况下不会更新 MainForm 上的控件。我怀疑这是因为我在它的本地副本上操作,而不是我添加到MainForm 的那些,但我不知道如何使它工作。我需要对CrossThreadInvoke 进行某种反击吗?
ProgressBar pb = Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls[counter] as ProgressBar;
pb.Value = e.ProgressPercentage;
但是,这似乎不必要地复杂,所以我想知道是否有更好的方法。
【问题讨论】:
-
设置新值后添加
pb.Update();,看看是否有帮助 -
@lokusking 不,遗憾的是没有
-
我重读了您说您的 MainForm 上已经有控件的部分。当然,您必须更新这些控件,而不是您正在创建但从未显示的控件。你也可以反过来做。保持现有代码不变,从 MainForm 中删除控件并将其替换为您在下载逻辑中创建的控件
-
@lokusking Ye,但是要在
MainForm上显示它们,我需要在开始进行任何更新之前添加它们。因此,即使我只是将拆分容器作为主窗体的一部分留在那里(因为另一半包含它的控件),我仍然需要将它们添加回MainForm整体,在任何更新之前。我认为这让我回到了原点。 -
很难说,在不了解完整代码的情况下,您的最佳做法是什么。
标签: c# winforms file download progress-bar