【问题标题】:Event operating on control in parent form在父窗体中对控件进行操作的事件
【发布时间】:2017-03-08 09:49:02
【问题描述】:

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

  1. 有一个SplitContainerListViewMainForm 的一个面板中。
  2. 我想要下载文件列表,为ListView 中的每个文件创建一个ProgressBar 和一个Label
  3. 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"));        
}

但是,pblb 在这种情况下不会更新 MainForm 上的控件。我怀疑这是因为我在它的本地副本上操作,而不是我添加到MainForm 的那些,但我不知道如何使它工作。我需要对CrossThreadInvoke 进行某种反击吗?

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

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

【问题讨论】:

  • 设置新值后添加pb.Update();,看看是否有帮助
  • @lok​​usking 不,遗憾的是没有
  • 我重读了您说您的 MainForm 上已经有控件的部分。当然,您必须更新这些控件,而不是您正在创建但从未显示的控件。你也可以反过来做。保持现有代码不变,从 MainForm 中删除控件并将其替换为您在下载逻辑中创建的控件
  • @lok​​usking Ye,但是要在MainForm 上显示它们,我需要在开始进行任何更新之前添加它们。因此,即使我只是将拆分容器作为主窗体的一部分留在那里(因为另一半包含它的控件),我仍然需要将它们添加回MainForm 整体,在任何更新之前。我认为这让我回到了原点。
  • 很难说,在不了解完整代码的情况下,您的最佳做法是什么。

标签: c# winforms file download progress-bar


【解决方案1】:

我给你做了一个小例子,它确实不漂亮,但应该让你知道如何实现进步。

我还注释了很多东西并插入了一些演示代码。

如果您在不同的线程/任务上,关键是使用 Controls.Invoke()-Method。

示例

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

}

我希望这能让您了解如何创建和更新进度条

【讨论】:

    猜你喜欢
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    相关资源
    最近更新 更多