2

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

我正在为用户能够下载的每个文件使用带有预定义行的 datagridview,并且每一行都有一个带有进度条的单元格。

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

这是我使用的代码:

要开始下载:

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

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

所以我希望有人能够帮助我解决这个问题,

提前致谢!

4

2 回答 2

2

你想要做的是使用另DownloadFileAsync一种方法:http: //msdn.microsoft.com/en-us/library/ms144197.aspx

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

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

    //(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);
}
于 2012-06-07T01:15:20.247 回答
0

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

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();
    }
}
于 2012-06-07T02:17:55.573 回答