以父表格控制的事件

时间:2017-03-08 09:49:03

标签: c# winforms file download progress-bar

我有一些文件要从ftp服务器下载。我想要实现的是:

  1. SplitContainer的其中一个面板中有一个ListView MainForm
  2. 我想要下载文件列表,为ProgressBar
  3. 中的每个文件创建LabelListView
  4. ProgressChanged事件中,我想显示ProgressBar上文件的当前进度以及Label
  5. 上的当前下载速度

    这是我的代码的最新版本:

    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"));        
    }
    

    但是,该事件中的pblb不会更新MainForm上的控件。我怀疑它是因为我操作它的本地副本,而不是我添加到MainForm的副本,但我不知道如何使其工作。我是否需要某种类型的计数器CrossThreadInvoke类似

    ProgressBar pb = Helper.CrossThreadInvoke(_sender, () => _sender.listView1.Controls[counter] as ProgressBar;
    pb.Value = e.ProgressPercentage;
    

    然而,这似乎是不必要的复杂,所以我想知道是否有更好的方法。

1 个答案:

答案 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