WebClient 异步下载器无法正常工作
WebClient asynchronous downloader not working properly
所以,我已经为此苦苦思索了一段时间。我是一个业余程序员,所以我并不总是知道自己做错了什么。
总之,我最近项目的前提:
我的朋友和我经常玩 MineCraft,但他们不是很聪明,而且我们并不总是四处寻找模组并向他们发送链接等等。所以我想我应该编写一些程序来自动下拉 mod,以便它们与服务器同步并同时获取服务器数据。
我正在使用免费的 FTP 主机,但我认为这不是这里的问题,原因会变得很清楚。
基本上,我想使用进度条,最好也使用标签来指示整个数据块的进度(所有 mod 加在一起……不超过 1GB - 小很多)。但是,我似乎 运行 关注有关异步选项的一些问题:
它会随机选择不下载它应该下载的文件
在声称完整之前可能没有完整下载文件
当消息框触发说它已完成所有项目的下载时,进度条可能已满 50%。
但是,由于在 Webclient 的同步使用中不存在进度报告事件,因此进度条无法正常工作,但当我 运行 BGworker 中的 syncro 时,它每次都能正确下载。但是,我失去了进度报告,这很重要....
所以,基本上:
- 有没有更好的实现方式?
这是在它准备好之前我需要开始工作的最后一块,所以我真的很想尝试这样做。感谢您的帮助!
编辑:更新代码:
Public Function GetDownloadSize(ByVal URL As String) As Long
Dim request As Net.FtpWebRequest = DirectCast(Net.WebRequest.Create(URL), Net.FtpWebRequest)
request.Method = Net.WebRequestMethods.Ftp.GetFileSize
request.Credentials = New Net.NetworkCredential(dl_user, dl_pass)
Dim response As Net.FtpWebResponse = DirectCast(request.GetResponse(), Net.FtpWebResponse)
Dim fileSize As Long = response.ContentLength
Return fileSize
End Function
Private Sub btn_sync_Click(sender As Object, e As EventArgs) Handles btn_sync.Click
Dim cont As DialogResult = MsgBox("Continue? " + (total_dl_size / 1000).ToString("N0") + " KB remain to be downloaded.", MsgBoxStyle.YesNo, "CAUTION!")
If cont = DialogResult.No Then
tb_warnings.AppendText("-ERR: User declined to synchronize files. Restart the application to sync.")
tb_warnings.AppendText(ControlChars.NewLine)
Label3.BackColor = Color.Firebrick
Return
End If
btn_sync.Enabled = False
btn_scan.Enabled = false
tb_warnings.AppendText("-Deleting outmoded/unused mods. Protected mods will be kept.")
For Each i As fdata_obj In deleted_files
My.Computer.FileSystem.DeleteFile(mc_dir + "\mods\" + i.name)
Next
tb_warnings.AppendText(ControlChars.NewLine)
tb_warnings.AppendText("-Deleting mod subdirectories to ensure no conflicts.")
tb_warnings.AppendText(ControlChars.NewLine)
For Each d In My.Computer.FileSystem.GetDirectories(mc_dir + "\mods")
My.Computer.FileSystem.DeleteDirectory(d, FileIO.DeleteDirectoryOption.DeleteAllContents)
Next
initialize_download()
End Sub
Private Sub initialize_download()
Dim wc As New System.Net.WebClient() ' SORRY, ASSUME THIS IS A PUBLIC VAR SO IT CAN BE REFERENCED ACROSS ITS OTHER METHODS
AddHandler wc.DownloadProgressChanged, AddressOf OnDownloadProgressChanged
AddHandler wc, AddressOf OnFileDownloadCompleted
Dim usr As String = "randouser"
Dim pass As String = "randopass"
For Each s In (From dl As fdata_obj In new_files Select dl_server + "/mods/" + mods_dir + "/" + dl.name).ToList
downloads.Enqueue(s)
Next
wc.Credentials = New Net.NetworkCredential(usr, pass)
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
end try
End Sub
Private Sub OnDownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs)
MsgBox("This is happening!")
total_dl = total_dl + e.BytesReceived
Dim percentage As Integer = (CType((total_dl / total_dl_size), Integer) * 100)
if percentage > 100 then
percentage = 100
endif
prog_update(percentage)
End Sub
delegate sub progress_update(byval prog as integer)
' POTENTIAL ISSUES HERE???????
private sub prog_update(byval prog as integer)
if progressbar1.invokerequired then
progressbar1.invoke(new prog_update(addressof progress),prog)
else
progressbar1.value = prog
Private Sub OnFileDownloadCompleted(ByVal sender As Net.WebClient, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
If e.Cancelled Then
MsgBox(e.Cancelled)
ElseIf Not e.Error Is Nothing Then
MsgBox(e.Error.Message)
Else
if downloads.count > 0 then
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
End Try
End If
End Sub
首先,您的进度条不起作用的主要原因是:
Dim percentage As Integer = (CType((total_dl / total_dl_size), Integer) * 100)
代码将首先计算 total_dl / total_dl_size
,假设结果为 0.34,然后它将其转换为整数,结果为 0(0.34 向下舍入为零,因为整数没有小数),最后将 0 乘以 100(结果仍然是 0)。
你要做的是先将被除数乘以 100,这样结果将从 0-100 而不是 0- 1: (total_dl * 100) / total_dl_size
.
至于thread-safety(调用)我总是使用我创建的这个extension method:
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Sub InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object())
If Parameters Is Nothing OrElse _
Parameters.Length = 0 Then Parameters = Nothing 'If Parameters is null or has a length of zero then no parameters should be passed.
If Control.InvokeRequired = True Then
Control.Invoke(Method, Parameters)
Else
Method.DynamicInvoke(Parameters)
End If
End Sub
End Module
(最好放在另一个文件中)
与 Lambda expressions(在 Visual Studio 2010 年引入)一起,将大大 简化您的调用。这是因为没有将 If InvokeRequired
模式放在任何地方:
If Me.InvokeRequired Then
Me.Invoke(New Action(AddressOf SomeMethod), params)
Else
SomeMethod()
End If
您只需输入:
Me.InvokeIfRequired(AddressOf SomeMethod, params)
扩展方法将为您完成剩下的工作。
如果您使用 lambda 表达式,您可以动态创建方法:
Me.InvokeIfRequired(Sub()
Label1.Text = "Hello world!"
ProgressBar1.Value += 1
End Sub)
现在,到你的代码。
我将你的代码分开了一些,这样更容易处理。对于初学者,我创建了一个更通用的方法,而不是 copy-pasting 下载代码到 DownloadFileCompleted
事件处理程序,称为 DownloadFile()
.
''' <summary>
''' Downloads a file from the specified URL with the specified credentials.
''' </summary>
''' <param name="URL">The URL of the file.</param>
''' <param name="Username">The username which to login with.</param>
''' <param name="Password">The password which to login with.</param>
''' <remarks></remarks>
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String)
If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!")
wc.Credentials = New NetworkCredential(dl_user, dl_pass)
total_dl_size = GetDownloadSize(URL, Username, Password)
Try
Dim FileName As String = Path.GetFileName(URL)
AppendWarning("Downloading " & FileName & "...")
wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName))
Catch ex As Exception
AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL))
End Try
End Sub
如您所见,我还制作了一个用于输出警告和错误消息的通用方法:
''' <summary>
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box.
''' </summary>
''' <param name="Text">The text to append.</param>
''' <remarks></remarks>
Private Sub AppendWarning(ByVal Text As String)
Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine))
End Sub
这是完整的代码,它适合我:
Private dl_user As String = "someusername"
Private dl_pass As String = "somepassword"
Private dl_urls As String() = {"URL1", "URL2"} 'Temporary. Use your own code.
Private total_dl_size As Long = 0
Private total_dl As Long = 0
Dim WithEvents wc As New System.Net.WebClient()
Dim downloads As New Queue(Of String)
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'Populate the download queue.
downloads.Enqueue(dl_urls(0)) 'Temporary. Use your own code here.
downloads.Enqueue(dl_urls(1))
End Sub
'The download button.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Do your pre-download stuff here.
DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the first file.
End Sub
''' <summary>
''' Downloads a file from the specified URL with the specified credentials.
''' </summary>
''' <param name="URL">The URL of the file.</param>
''' <param name="Username">The username which to login with.</param>
''' <param name="Password">The password which to login with.</param>
''' <remarks></remarks>
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String)
If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!")
wc.Credentials = New NetworkCredential(dl_user, dl_pass) 'Set the credentials.
total_dl_size = GetDownloadSize(URL, Username, Password) 'Get the size of the current file.
Try
Dim FileName As String = Path.GetFileName(URL) 'Get the current file's name.
AppendWarning("Downloading " & FileName & "...") 'Download notice.
wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName)) 'Download the file to the desktop (use your own path here).
Catch ex As Exception
AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL))
End Try
End Sub
''' <summary>
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box.
''' </summary>
''' <param name="Text">The text to append.</param>
''' <remarks></remarks>
Private Sub AppendWarning(ByVal Text As String)
Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine))
End Sub
Private Sub wc_DownloadProgressChanged(sender As Object, e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.InvokeIfRequired(Sub()
Dim Progress As Integer = CType(Math.Round((e.BytesReceived * 100) / total_dl_size), Integer)
If Progress > 100 Then Progress = 100
If Progress < 0 Then Progress = 0
ProgressBar1.Value = Progress
End Sub)
End Sub
Private Sub wc_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
If e.Cancelled Then
MessageBox.Show(e.Cancelled)
ElseIf Not e.Error Is Nothing Then
MessageBox.Show(e.Error.Message)
Else
If downloads.Count > 0 Then
DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the next file.
Else
AppendWarning("Download complete!")
End If
End If
End Sub
其他一些注意事项:
用MsgBox()
function exists purely for backwards compatibility. You should use .NET's standard MessageBox.Show()
method代替。
字符串连接应该使用和号 (&
) 而不是加号 (+
)。 See why.
连接路径应始终使用 Path.Combine()
完成,因为它将确保创建正确的路径。如果您输入任何无效内容,它会抛出异常。
用法:
Path.Combine(Path1, Path2, Path3, ...)
Path.Combine("C:\", "Foo") 'Results in: C:\Foo
Path.Combine("C:\", "Foo", "Bar", "Hello World.txt") 'Results in: C:\Foo\Bar\Hello World.txt
希望对您有所帮助!
所以,我已经为此苦苦思索了一段时间。我是一个业余程序员,所以我并不总是知道自己做错了什么。
总之,我最近项目的前提:
我的朋友和我经常玩 MineCraft,但他们不是很聪明,而且我们并不总是四处寻找模组并向他们发送链接等等。所以我想我应该编写一些程序来自动下拉 mod,以便它们与服务器同步并同时获取服务器数据。
我正在使用免费的 FTP 主机,但我认为这不是这里的问题,原因会变得很清楚。
基本上,我想使用进度条,最好也使用标签来指示整个数据块的进度(所有 mod 加在一起……不超过 1GB - 小很多)。但是,我似乎 运行 关注有关异步选项的一些问题:
它会随机选择不下载它应该下载的文件
在声称完整之前可能没有完整下载文件
当消息框触发说它已完成所有项目的下载时,进度条可能已满 50%。
但是,由于在 Webclient 的同步使用中不存在进度报告事件,因此进度条无法正常工作,但当我 运行 BGworker 中的 syncro 时,它每次都能正确下载。但是,我失去了进度报告,这很重要....
所以,基本上:
- 有没有更好的实现方式?
这是在它准备好之前我需要开始工作的最后一块,所以我真的很想尝试这样做。感谢您的帮助!
编辑:更新代码:
Public Function GetDownloadSize(ByVal URL As String) As Long
Dim request As Net.FtpWebRequest = DirectCast(Net.WebRequest.Create(URL), Net.FtpWebRequest)
request.Method = Net.WebRequestMethods.Ftp.GetFileSize
request.Credentials = New Net.NetworkCredential(dl_user, dl_pass)
Dim response As Net.FtpWebResponse = DirectCast(request.GetResponse(), Net.FtpWebResponse)
Dim fileSize As Long = response.ContentLength
Return fileSize
End Function
Private Sub btn_sync_Click(sender As Object, e As EventArgs) Handles btn_sync.Click
Dim cont As DialogResult = MsgBox("Continue? " + (total_dl_size / 1000).ToString("N0") + " KB remain to be downloaded.", MsgBoxStyle.YesNo, "CAUTION!")
If cont = DialogResult.No Then
tb_warnings.AppendText("-ERR: User declined to synchronize files. Restart the application to sync.")
tb_warnings.AppendText(ControlChars.NewLine)
Label3.BackColor = Color.Firebrick
Return
End If
btn_sync.Enabled = False
btn_scan.Enabled = false
tb_warnings.AppendText("-Deleting outmoded/unused mods. Protected mods will be kept.")
For Each i As fdata_obj In deleted_files
My.Computer.FileSystem.DeleteFile(mc_dir + "\mods\" + i.name)
Next
tb_warnings.AppendText(ControlChars.NewLine)
tb_warnings.AppendText("-Deleting mod subdirectories to ensure no conflicts.")
tb_warnings.AppendText(ControlChars.NewLine)
For Each d In My.Computer.FileSystem.GetDirectories(mc_dir + "\mods")
My.Computer.FileSystem.DeleteDirectory(d, FileIO.DeleteDirectoryOption.DeleteAllContents)
Next
initialize_download()
End Sub
Private Sub initialize_download()
Dim wc As New System.Net.WebClient() ' SORRY, ASSUME THIS IS A PUBLIC VAR SO IT CAN BE REFERENCED ACROSS ITS OTHER METHODS
AddHandler wc.DownloadProgressChanged, AddressOf OnDownloadProgressChanged
AddHandler wc, AddressOf OnFileDownloadCompleted
Dim usr As String = "randouser"
Dim pass As String = "randopass"
For Each s In (From dl As fdata_obj In new_files Select dl_server + "/mods/" + mods_dir + "/" + dl.name).ToList
downloads.Enqueue(s)
Next
wc.Credentials = New Net.NetworkCredential(usr, pass)
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
end try
End Sub
Private Sub OnDownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs)
MsgBox("This is happening!")
total_dl = total_dl + e.BytesReceived
Dim percentage As Integer = (CType((total_dl / total_dl_size), Integer) * 100)
if percentage > 100 then
percentage = 100
endif
prog_update(percentage)
End Sub
delegate sub progress_update(byval prog as integer)
' POTENTIAL ISSUES HERE???????
private sub prog_update(byval prog as integer)
if progressbar1.invokerequired then
progressbar1.invoke(new prog_update(addressof progress),prog)
else
progressbar1.value = prog
Private Sub OnFileDownloadCompleted(ByVal sender As Net.WebClient, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
If e.Cancelled Then
MsgBox(e.Cancelled)
ElseIf Not e.Error Is Nothing Then
MsgBox(e.Error.Message)
Else
if downloads.count > 0 then
Dim urix As String = downloads.Dequeue
Try
wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix))
Catch ex As Exception
MsgBox(ex.Message)
If tb_warnings.InvokeRequired = True Then
tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix)
Else
tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix))
tb_warnings.AppendText(ControlChars.NewLine)
End If
End Try
End If
End Sub
首先,您的进度条不起作用的主要原因是:
Dim percentage As Integer = (CType((total_dl / total_dl_size), Integer) * 100)
代码将首先计算 total_dl / total_dl_size
,假设结果为 0.34,然后它将其转换为整数,结果为 0(0.34 向下舍入为零,因为整数没有小数),最后将 0 乘以 100(结果仍然是 0)。
你要做的是先将被除数乘以 100,这样结果将从 0-100 而不是 0- 1: (total_dl * 100) / total_dl_size
.
至于thread-safety(调用)我总是使用我创建的这个extension method:
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Sub InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object())
If Parameters Is Nothing OrElse _
Parameters.Length = 0 Then Parameters = Nothing 'If Parameters is null or has a length of zero then no parameters should be passed.
If Control.InvokeRequired = True Then
Control.Invoke(Method, Parameters)
Else
Method.DynamicInvoke(Parameters)
End If
End Sub
End Module
(最好放在另一个文件中)
与 Lambda expressions(在 Visual Studio 2010 年引入)一起,将大大 简化您的调用。这是因为没有将 If InvokeRequired
模式放在任何地方:
If Me.InvokeRequired Then
Me.Invoke(New Action(AddressOf SomeMethod), params)
Else
SomeMethod()
End If
您只需输入:
Me.InvokeIfRequired(AddressOf SomeMethod, params)
扩展方法将为您完成剩下的工作。
如果您使用 lambda 表达式,您可以动态创建方法:
Me.InvokeIfRequired(Sub()
Label1.Text = "Hello world!"
ProgressBar1.Value += 1
End Sub)
现在,到你的代码。
我将你的代码分开了一些,这样更容易处理。对于初学者,我创建了一个更通用的方法,而不是 copy-pasting 下载代码到 DownloadFileCompleted
事件处理程序,称为 DownloadFile()
.
''' <summary>
''' Downloads a file from the specified URL with the specified credentials.
''' </summary>
''' <param name="URL">The URL of the file.</param>
''' <param name="Username">The username which to login with.</param>
''' <param name="Password">The password which to login with.</param>
''' <remarks></remarks>
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String)
If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!")
wc.Credentials = New NetworkCredential(dl_user, dl_pass)
total_dl_size = GetDownloadSize(URL, Username, Password)
Try
Dim FileName As String = Path.GetFileName(URL)
AppendWarning("Downloading " & FileName & "...")
wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName))
Catch ex As Exception
AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL))
End Try
End Sub
如您所见,我还制作了一个用于输出警告和错误消息的通用方法:
''' <summary>
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box.
''' </summary>
''' <param name="Text">The text to append.</param>
''' <remarks></remarks>
Private Sub AppendWarning(ByVal Text As String)
Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine))
End Sub
这是完整的代码,它适合我:
Private dl_user As String = "someusername"
Private dl_pass As String = "somepassword"
Private dl_urls As String() = {"URL1", "URL2"} 'Temporary. Use your own code.
Private total_dl_size As Long = 0
Private total_dl As Long = 0
Dim WithEvents wc As New System.Net.WebClient()
Dim downloads As New Queue(Of String)
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'Populate the download queue.
downloads.Enqueue(dl_urls(0)) 'Temporary. Use your own code here.
downloads.Enqueue(dl_urls(1))
End Sub
'The download button.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Do your pre-download stuff here.
DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the first file.
End Sub
''' <summary>
''' Downloads a file from the specified URL with the specified credentials.
''' </summary>
''' <param name="URL">The URL of the file.</param>
''' <param name="Username">The username which to login with.</param>
''' <param name="Password">The password which to login with.</param>
''' <remarks></remarks>
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String)
If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!")
wc.Credentials = New NetworkCredential(dl_user, dl_pass) 'Set the credentials.
total_dl_size = GetDownloadSize(URL, Username, Password) 'Get the size of the current file.
Try
Dim FileName As String = Path.GetFileName(URL) 'Get the current file's name.
AppendWarning("Downloading " & FileName & "...") 'Download notice.
wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName)) 'Download the file to the desktop (use your own path here).
Catch ex As Exception
AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL))
End Try
End Sub
''' <summary>
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box.
''' </summary>
''' <param name="Text">The text to append.</param>
''' <remarks></remarks>
Private Sub AppendWarning(ByVal Text As String)
Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine))
End Sub
Private Sub wc_DownloadProgressChanged(sender As Object, e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.InvokeIfRequired(Sub()
Dim Progress As Integer = CType(Math.Round((e.BytesReceived * 100) / total_dl_size), Integer)
If Progress > 100 Then Progress = 100
If Progress < 0 Then Progress = 0
ProgressBar1.Value = Progress
End Sub)
End Sub
Private Sub wc_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
If e.Cancelled Then
MessageBox.Show(e.Cancelled)
ElseIf Not e.Error Is Nothing Then
MessageBox.Show(e.Error.Message)
Else
If downloads.Count > 0 Then
DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the next file.
Else
AppendWarning("Download complete!")
End If
End If
End Sub
其他一些注意事项:
用
MsgBox()
function exists purely for backwards compatibility. You should use .NET's standardMessageBox.Show()
method代替。字符串连接应该使用和号 (
&
) 而不是加号 (+
)。 See why.连接路径应始终使用
Path.Combine()
完成,因为它将确保创建正确的路径。如果您输入任何无效内容,它会抛出异常。用法:
Path.Combine(Path1, Path2, Path3, ...) Path.Combine("C:\", "Foo") 'Results in: C:\Foo Path.Combine("C:\", "Foo", "Bar", "Hello World.txt") 'Results in: C:\Foo\Bar\Hello World.txt
希望对您有所帮助!