如何单独更新进度条(同时下载)

本文关键字:下载 何单独 更新 | 更新日期: 2023-09-27 18:36:28

我目前正在尝试向我的应用程序添加并行下载,但我不知道如何处理 DownloadProgressChangedEvent 以在多个进度条中显示进度。

我正在使用一个数据网格视图,其中包含用户能够下载的每个文件的预定义行,并且每行都有一个带有进度条的单元格。

现在的问题是,我不知道如何单独更新每个进度条,因为现在,所有选定的进度条都显示相同的百分比,它们只是在download1和download2的进度之间跳跃。

这是我使用的代码:

要开始下载:

private void download_button_Click(object sender, EventArgs e)
    {
        start = DateTime.Now;
        download_button.Enabled = false;
        Rows = dataGridView1.Rows.Count;
        Checked = 0;
        CheckedCount = 0;
            //count the selected rows
            for (i = 0; i < Rows; i++)
            {
                Checked = Convert.ToInt32(dataGridView1.Rows[i].Cells["checkboxcol"].FormattedValue);
                CheckedCount += Checked;
                richTextBox3.Text = CheckedCount.ToString();
            }

        for (int z = 1; z < CheckedCount; z++)
        {             
            _MultipleWebClients = new WebClient();
            _MultipleWebClients.DownloadFileCompleted += new AsyncCompletedEventHandler(_DownloadFileCompleted);
            _MultipleWebClients.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(_DownloadProgressChanged);
            _MultipleWebClients.DownloadFileAsync(new Uri(_downloadUrlList[z].ToString()), @"F:'test" + z + ".mp4");     
        }
    }

(我也无法同时下载两个以上的文件 - 在前两个完成之前,第三次下载不会开始)


下载进度更改事件:

    private void _DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        for (int c = 0; c < CheckedCount; c++)
        {
            dataGridView1.Rows[_downloadRowNrList[c]].Cells[3].Value = e.ProgressPercentage;
        }
        float size = ((e.TotalBytesToReceive / 1024) / 1024);
        label1.Text = size.ToString();
        double dn = (double)e.BytesReceived / 1024.0 / (DateTime.Now - start).TotalSeconds;
        label2.Text = (dn.ToString("n") + " KB/s) " + e.ProgressPercentage);        
    }

问题可能是,所有进度条都使用相同的下载进度更改事件,但我不确定如何在不知道所需数量的情况下创建多个这些事件......

所以我希望有人能够帮助我,

提前感谢!

如何单独更新进度条(同时下载)

您要做的是使用其他DownloadFileAsync方法:http://msdn.microsoft.com/en-us/library/ms144197.aspx

第三个参数是 userToken,它作为DownloadProgressChangedEventArgs的一部分传递(它位于 UserState 属性中)。

因此,当您进行DownloadFileAsync调用时,传入一个唯一令牌(整数或其他内容),然后可以将其与需要更新的进度栏相关联。

    //(Snip)
    //in download_button_Click, pass the row you are updating to the event.
    for (int z = 1; z < CheckedCount; z++)
    {             
        _MultipleWebClients = new WebClient();
        _MultipleWebClients.DownloadFileCompleted += new AsyncCompletedEventHandler(_DownloadFileCompleted);
        _MultipleWebClients.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(_DownloadProgressChanged);
        _MultipleWebClients.DownloadFileAsync(new Uri(_downloadUrlList[z].ToString()), @"F:'test" + z + ".mp4", dataGridView1.Rows[z]);     
    }
}
private void _DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    var rowToUpdate = (DataGridViewRow)e.UserState;
    RowToUpdate["ProgressBar"].Value = e.ProgressPercentage;
    RowToUpdate["TextProgress"].Value = e.ProgressPercentage;
    RowToUpdate["BytesToRecive"].Value = ((e.TotalBytesToReceive / 1024) / 1024).ToString();
    double dn = (double)e.BytesReceived / 1024.0 / (DateTime.Now - start).TotalSeconds;
    RowToUpdate["Speed"].Value = (dn.ToString("n") + " KB/s) " + e.ProgressPercentage);
}

听起来你需要一个进度条来进行多部分进度:

public partial class ProgressBarEx : ProgressBar
{
    private readonly Dictionary<Guid, double> _partsProgress =
        new Dictionary<Guid, double>();
    private readonly Dictionary<Guid, double> _partsSizes =
        new Dictionary<Guid, double>();
    private double _value;
    private double _maximum;
    public ProgressBarEx()
    {
        this.InitializeComponent();
    }
    public int Parts
    {
        get { return this._partsSizes.Count; }
    }
    public new int Minimum { get; private set; }
    public new double Maximum
    {
        get { return this._maximum; }
        private set
        {
            this._maximum = value;
            base.Maximum = (int)value;
        }
    }
    public new double Value
    {
        get { return this._value; }
        private set
        {
            this._value = value;
            base.Value = (int)value;
        }
    }
    [Obsolete("Not useable in ProgressBarEx.")]
    public new int Step
    {
        get { return 0; }
    }
    public Guid AddPart(double size)
    {
        if (size <= 0)
        {
            throw new ArgumentException("size");
        }
        var partId = Guid.NewGuid();
        this.Maximum += size;
        this._partsSizes.Add(partId, size);
        this._partsProgress.Add(partId, 0);
        return partId;
    }
    public bool RemovePart(Guid partId)
    {
        double size;
        if (!this._partsSizes.TryGetValue(partId, out size))
        {
            return false;
        }
        this.Maximum -= size;
        this._partsSizes.Remove(partId);
        this.Value -= this._partsProgress[partId];
        this._partsProgress.Remove(partId);
        return true;
    }
    public bool ContainsPart(Guid partId)
    {
        return this._partsSizes.ContainsKey(partId);
    }
    public double GetProgress(Guid partId)
    {
        return this._partsProgress[partId];
    }
    public void SetProgress(Guid partId, double progress)
    {
        if (progress < 0 || this._partsSizes[partId] < progress)
        {
            throw new ArgumentOutOfRangeException("progress");
        }
        this.Value += progress - this._partsProgress[partId];
        this._partsProgress[partId] = progress;
    }
    public void AddProgress(Guid partId, double progress)
    {
        this.SetProgress(partId, progress + this._partsProgress[partId]);
    }
    [Obsolete("Not useable in ProgressBarEx.")]
    public new void PerformStep()
    {
    }
}

用法示例:

public Form1()
{
    InitializeComponent();
    var pbe = new ProgressBarEx {Location = new Point(100, 100)};
    this.Controls.Add(pbe);
    for (var i = 0; i < 4; i++)
    {
        var size = i * 10 + 30;
        var partId = pbe.AddPart(size);
        var pb = new ProgressBar
                     {
                         Maximum = size,
                         Location = new Point(100, i * 30 + 130)
                     };
        this.Controls.Add(pb);
        var timer = new Timer {Interval = 1000 + i * 100};
        timer.Tick += (sender, args) =>
                          {
                              pb.Value += 5;
                              pbe.AddProgress(partId, 5);
                              if (pb.Value == pb.Maximum)
                              {
                                  timer.Stop();
                              }
                          };
        timer.Start();
    }
}