我正在开发一个基本上有几十个复选框的项目,它会在按下按钮后异步下载与所选复选框对应的文件。
下载功能正常,但有些文件的大小更大,我希望能够根据需要取消每个单独的下载。我正在通过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%有用,但它可能是朝着正确方向迈出的一步。
答案 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"; }
}
希望有所帮助。