使用CancelAsync()停止正在进行的特定webclient下载

时间:2014-01-03 20:52:26

标签: vb.net multithreading visual-studio asynchronous webclient

我正在开发一个基本上有几十个复选框的项目,它会在按下按钮后异步下载与所选复选框对应的文件。

下载功能正常,但有些文件的大小更大,我希望能够根据需要取消每个单独的下载。我正在通过datalistview监视下载进度,并为每次下载都“取消”DataGridViewButtonColumn。不幸的是,CancelAsync()似乎不接受参数 - 我希望能够做类似的事情:CancelAsync(url)。我正在使用单个webclient,它似乎对实际下载没有任何不利影响,但我是否需要为每个单独的下载声明一个单独的webclient才能够单独取消它们? (反过来又为每个人完成/更改了AddHandlers?)

我希望有一个更简单的解决方案,但如果没有,我愿意这样做。或者,有没有办法取消当前正在进行的所有下载?

[编辑] 这是我在datagridview中取消按钮的当前代码:

Private Sub CellContentClick(ByVal sender As DataGridView, _
                     ByVal e As DataGridViewCellEventArgs) _
                     Handles DataGridView1.CellContentClick
    'make sure click not on header and column is of type ButtonColumn
    If e.RowIndex >= 0 AndAlso sender.Columns(e.ColumnIndex).GetType() = _
                               GetType(DataGridViewButtonColumn) Then
        'TODO - Execute Code Here
        cli.CancelAsync()
        cli.Dispose()
    End If
End Sub

目前这将取消最后一次下载 - 我找到了这个问题但是我在类级别声明了webclient - 所以每次都被覆盖。我正在查看WebClient Class,但我还没有找到任何东西。是否可以做这样的事情(请记住这是伪代码,我知道这是不正确的):

For each webclient in currentWebclients
    If webclientUrl = url Then CancelAsync()
Next

[编辑2]

以下是我在添加每个下载时设置datagridview的方法:

    Dim n As Integer = DataGridView1.Rows.Add()
    DataGridView1.Rows.Item(n).Cells(0).Value = programName

然后我更新每次下载的完成百分比:

    For Rowindex = DataGridView1.Rows.Count - 1 To 0 Step -1
        If DataGridView1.Rows(Rowindex).Cells(0).Value = programName Then
            DataGridView1.Rows.Item(Rowindex).Cells(1).Value = percent
            DataGridView1.Rows.Item(Rowindex).Cells(3).Value = "Cancel"
        End If
    Next

百分比来自DownloadProgressChanged:

Dim percent As String = e.ProgressPercentage.ToString

Cells(3)是DataGridViewButtonColumn,即每次下载的“取消”按钮

单元格(2)保留用于错误消息

在DownloadFileCompleted中,我处理

If e.Cancelled = True

此外,当给定的下载完成时,我清除行:

    For Rowindex = DataGridView1.Rows.Count - 1 To 0 Step -1
        If DataGridView1.Rows(Rowindex).Cells(0).Value = programName Then
            DataGridView1.Rows.RemoveAt(Rowindex)
        End If
    Next

原样,除取消按钮外,一切都正常。我遇到的问题是如何在上面的CellContentClick子中引用特定的webclient。

我在CellContentClick中做了一些测试:

        Dim i = DataGridView1.CurrentRow.Index
        MessageBox.Show(DataGridView1.Item(0, i).Value)

当我单击DataGridViewButtonColumn中的按钮时,这确实显示了下载的名称(位于第一个单元格中) - 不是100%有用,但它可能是朝着正确方向迈出的一步。

1 个答案:

答案 0 :(得分:0)

自从你发布以来,我一直在阅读并尝试解决这个问题。

WebClient不支持多个连接,当您发现每次都在类级别覆盖它时,您实际捕获了这些连接。

如果我没有弄错的话,DataGridView有一个对象或一些其他属性,它们本质上允许你在其行内隐藏相关的数据对象。您需要为每次下载执行此操作,以便您可以执行类似于上面建议的操作:

For each webclient in currentWebclients
    If webclientUrl = url Then CancelAsync()
Next

您可以为WebClient创建一个chiild类,它将公开一个漂亮的人类可重用的字符串放入该行,或者将WebClient对象放入集合中并在必要时在客户端上调用CancelAsync

编辑:这里有一些代码说明了我的意思:

    private void button1_Click(object sender, EventArgs e)
    {
        Foo bar = new Foo();
        Foo bar2 = new Foo();
        bar.fooInt = 12;
        bar2.fooInt = 13;

        dataGridView1.Rows.Add(bar, bar2);

        (dataGridView1.Rows[0].Cells[0].Value as Foo).fooInt = 3;
    }

    private class Foo
    {
        public Foo() { }
        public int fooInt = 0;
        public override string ToString()
        {
            return "Foo Int is: " + fooInt.ToString();
        }
    }

在这种情况下,dataGridView1是我添加到表单并手动创建列的表单组件。使用数据网格视图,您可以将对象添加到单元格,只要您覆盖ToString()方法以显示所需内容,它就会显示正确的文本。在您的情况下,您将需要一个类从WebClient继承,只在ToString()中公开“取消”。

运行上面的代码以查看它是如何工作的,但这基本上就是你想要的:

    private function someCreationFunction() 
    {
        WebClientChild wcc = new WebClientChild();
        dataGridView1.Rows.Add(wcc, "");
    }

    private void CancelButton_Click(object sender, EventArgs e)
    {
        (dataGridView1.Rows[rowIndex].Cells[rowIndex].Value as WebClientChild).CancelAsync();

    }

    private class WebClientChild : WebClient
    {
        public WebClientChild() : base() { }
        public override string ToString() { return "Cancel"; }
    }

希望有所帮助。