我有一些文件要从ftp服务器下载。我想要实现的是:
SplitContainer
的其中一个面板中有一个ListView
MainForm
。ProgressBar
Label
和ListView
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;
然而,这似乎是不必要的复杂,所以我想知道是否有更好的方法。
答案 0 :(得分:0)
我已经为你做了一个很小的例子,它真的不漂亮,但应该让你知道如何实现进步。
此外,我已经评论了很多内容并插入了一些演示代码。
关键是使用Controls.Invoke() - 方法,如果你在不同的线程/任务。
示例强>
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
var l = new List<string>();
for (int i = 0; i < 10; i++) {
l.Add("Some Text" + i);
}
Task.Factory.StartNew(async () => {
await GetFiles(l, this);
});
}
private int ctrlCount = 0;
public void AddControlToListView(Control c) {
if (c is Label) {
c.Location = new Point(205, ctrlCount * c.Height + 5);
} else {
c.Location = new Point(5, ctrlCount * c.Height + 5);
}
if (this.listView1.InvokeRequired) {
this.listView1.Invoke(new Action<Control>(this.listView1.Controls.Add), c);
this.listView1.Invoke(new Action(this.listView1.Update));
} else {
this.listView1.Controls.Add(c);
this.listView1.Update();
}
ctrlCount++;
}
internal async Task GetFiles(IEnumerable<string> urlList, Form1 parent) {
//string dir = Environment.CurrentDirectory + "\\updates";
//Directory.CreateDirectory(dir);
var tasks = new List<Task>();
foreach (var url in urlList)
tasks.Add(DownloadFile(url, ""));
await Task.WhenAll(tasks);
}
internal async Task DownloadFile(string url, string dir) {
string filename = "";// Helper.GetFilenameFromUrl(url);
ProgressBar pb = CreateFileDownloadBar();
Label lb = CreateFileDownloadLabel();
this.AddControlToListView(pb);
this.AddControlToListView(lb);
Stopwatch sw = new Stopwatch();
//Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls.Add(pb));
//Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls.Add(lb));
await Task.Factory.StartNew(() => {
for (int i = 1; i < 11; i++) {
pb.Invoke(new MethodInvoker(delegate {
pb.Value = i * 10;
}));
lb.Invoke(new MethodInvoker(delegate {
lb.Text = (i * 10).ToString();
}));
Thread.Sleep(500);
}
});
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() {
Text = "Hello"
//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"));
}
}
我希望这可以让您了解如何创建和更新ProgressBars