-
[2008] retrieving bytes for progress bar
hi, how do i retrieve the bytes being downloaded as well as the size of the download (total bytes) preferably with the webclient method if possible as this is what im using to download the file. Once i have retrieved the bytes, how do i calaculate it into a percentage and show it on an xp style progress bar.
any help to do any of this would be great!
thank you
-
Re: [2008] retrieving bytes for progress bar
If you want to show a download progress then you have two choices:
1. Call My.Computer.Network.DownloadFile and let it handle all that for you.
2. Call WebClient.DownloadFileAsync and handle the DownloadProgressChanged and DownloadFileCompleted events. You can then create your own ProgressBar and update it in the event handlers.
The second option is more complex but affords more control as a result, which is generally the case.
-
Re: [2008] retrieving bytes for progress bar
im going to use method 2. How would i use this in a background worker?
can you make this a bit more clear please, maybe give some example code, there isnt very much help on this subject out there
-
Re: [2008] retrieving bytes for progress bar
Have a look at jmcillhinneys signature. Let me know if you find anything on the subject there ;)
-
Re: [2008] retrieving bytes for progress bar
ok i have just used the following code;
Code:
For i As Integer = 1 To 100
'Raise the ProgressChanged event in the UI thread.
worker.ReportProgress(i, i & " iterations complete")
client.DownloadFile("http://wiikey.elementfx.com/Firmware/" & listbox, DownloadDirectoryOverall)
''Perform some time-consuming operation here.
'Threading.Thread.Sleep(250)
Next i
the problem is,when it gets to the download part it stops executing the code and downloads the file, so it cant go through the cycle. Its like having a stop command there until the download has completed.
anyway round this?
-
Re: [2008] retrieving bytes for progress bar
I was interested in this too.
Declared globally in the class:
VB Code:
Private WithEvents mWebClient As New WebClient
Private mDownloadedDummy As Boolean = False
Inside a download function I had:
VB Code:
mfUpdateStatusBarText(String.Format("Downloading {0}...", Path.GetFileName(mFilePathMp3)), False)
mWebClient.DownloadFileAsync(New System.Uri(mUrlPathMp3), mFilePathMp3)
While mDownloadedDummy = False
' wait
End While
and then:
VB Code:
Private Sub mWebClient_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles mWebClient.DownloadFileCompleted
mDownloadedDummy = True
End Sub
Private Sub mWebClient_DownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles mWebClient.DownloadProgressChanged
mProgressDiscsMax = CInt(e.TotalBytesToReceive)
mProgressDiscsCurrent = CInt(e.BytesReceived)
End Sub
For some reason the mWebClient_DownloadProgressChanged event doesnt get fired.
Is there anything I am missing?
Thanks. :)
-
Re: [2008] retrieving bytes for progress bar
spikeyredcactus, you would NOT use a BackgroundWorker at all. You'd do EXACTLY what I said, which McoreD has demonstrated.
McoreD, what's the point of performing an asynchronous operation and then blocking the main thread until it completes? Not only that, you're blocking using busy waiting:
vb.net Code:
While mDownloadedDummy = False
' wait
End While
How many processor cycles will be soaked up by that loop spinning endlessly?
The point of asynchronous programming is that it does NOT block the current thread while it's executing. If that's not what you want then use My.Computer.Network.DownloadFile with one of the overloads that displays a progress dialogue. If you DO want an asynchronous operation then I used this and it worked exactly as it should:
vb.net Code:
Public Class Form1
Private WithEvents wc As New Net.WebClient
Private filePath As String = "http://static.slysoft.com/SetupCloneDVDmobile.exe"
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.wc.DownloadFileAsync(New Uri(Me.filePath), _
IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, _
IO.Path.GetFileName(Me.filePath)))
End Sub
Private Sub wc_DownloadFileCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
If e.Error Is Nothing Then
Me.Label1.Text = "Download Complete"
Else
Me.Label1.Text = e.Error.ToString()
End If
End Sub
Private Sub wc_DownloadProgressChanged(ByVal sender As Object, _
ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.ProgressBar1.Maximum = CInt(e.TotalBytesToReceive)
Me.ProgressBar1.Value = CInt(e.BytesReceived)
Me.Label1.Text = e.ProgressPercentage & "% Complete"
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.wc.CancelAsync()
End Sub
End Class
-
Re: [2008] retrieving bytes for progress bar
jmcilhinney,
Sorry I wasn't in detail earlier. The main application thread isn't blocked.
I have a BackgroundWorker that performs various tasks. Downloading this mp3 file is part of a background task. What I am blocking is the BackgroundWorker.
Alternatively I could let the main thread fire the WebClient and start the BackgroundWorker job after WebClient has finished downloading. So the BackgroundWorker will already have the mp3 file to work with.
Thansk for the code you have showed, I will be looking into it.
-
Re: [2008] retrieving bytes for progress bar
I am still wasting CPU cycles (this is just R&D - I wouldn't let that happen in a release build anyway :D) by that while loop which I am getting rid of now.
I see what I have done wrong. When the background worker was busy with the while thread, it didn't respond to update progress bar. (I think).
Will let know result...
-
Re: [2008] retrieving bytes for progress bar
McoreD, I repeat to you what I said posted for spikeyredcactus. The whole point of calling DownloadFileAsync is that the actual download takes place in a background thread. There's no point call it from the DoWork event handler of a BackgroundWorker, which itself is executed in a background thread. The reason you use asynchronous programming is almost universally to prevent blocking the UI thread while you perform a time-consuming operation. If you're executing in a background thread then the UI thread isn't blocked anyway, so why would you need to create yet another thread?
Calling DownloadFileAsync on a WebClient is akin to calling RunWorkerAsync on a BackgroundWorker. Both of them will start executing some work on a background thread without blocking the thread they are called on, which would be the UI thread.
-
Re: [2008] retrieving bytes for progress bar
Quote:
Originally Posted by jmcilhinney
Calling DownloadFileAsync on a WebClient is akin to calling RunWorkerAsync on a BackgroundWorker. Both of them will start executing some work on a background thread without blocking the thread they are called on, which would be the UI thread.
Oh my god. So I could have just simply used mWebClient.DownloadFile inside BackgroundWorker and still have access to mWebClient.DownloadFileCompleted?
I thought not because the function goes as
Private Sub mWebClient_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles mWebClient.DownloadFileCompleted
Quote:
Originally Posted by jmcilhinney
If you're executing in a background thread then the UI thread isn't blocked anyway, so why would you need to create yet another thread?
I thought that's the only way to have access to mWebClient.DownloadFileCompleted, am I wrong?
By the way, as soon as I called mWebClient from the main app as per your example, everything worked wonderfully. :)
Edit:
Quote:
Originally Posted by jmcilhinney
If that's not what you want then use My.Computer.Network.DownloadFile with one of the overloads that displays a progress dialogue
Wished I read this properly earlier:
http://img404.imageshack.us/img404/7...02pmkn7.th.png
-
Re: [2008] retrieving bytes for progress bar
Quote:
Originally Posted by ~*McoreD*~
Oh my god. So I could have just simply used mWebClient.DownloadFile inside BackgroundWorker and still have access to mWebClient.DownloadFileCompleted?
I thought not because the function goes as
Private Sub mWebClient_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles mWebClient.DownloadFileCompleted
I thought that's the only way to have access to mWebClient.DownloadFileCompleted, am I wrong?
By the way, as soon as I called mWebClient from the main app as per your example, everything worked wonderfully. :)
The whole point of using the asynchronous download method is so that you can send it off on its way and carry on with what you were doing. The whole point of the events is so that your UI can be notified periodically of how the asynchronous operation is going without placing a burden on the UI thread. What other reason would you want to handle those events for other than to notify the user by updating the UI? That means you want to initiate the operation and be notified of the progress of the operation in the UI thread without being burdened with the actual work of downloading in the UI thread. That's the whole point.
-
Re: [2008] retrieving bytes for progress bar
wow this has sparked allot of debate, i have bo idea what you guys are actually talking about, this proberly isnt a good subject for a noob like me to get into, but i need to for my project.
so im gonna see if i can get my head round jmcihnney's code.
Cheers!
*EDIT*
what is an asynchronous opperation? i want the main window to be free whilst it downloads, thats why i used the background worker. But now i shouldnt? im confused what do i need to do?
-
Re: [2008] retrieving bytes for progress bar
spikeyredcactus,
jm explained it perfectly - what an async operation means:
The whole point of using the asynchronous download method is so that you can send it off on its way and carry on with what you were doing. The whole point of the events is so that your UI can be notified periodically of how the asynchronous operation is going without placing a burden on the UI thread.
You need to do exactly what jm demonstrated in post #7.
-
Re: [2008] retrieving bytes for progress bar
To be more specific:
A synchronous, or blocking, method is one that does not return until the operation has completed, thus blocking the thread that called it from proceeding.
An asynchronous, or non-blocking, method is one that returns immediately and the operation it initiated carries on in the background.
The only way that an operation can be processed in the background is on a different thread, but with asynchronous methods you don't have to explicitly create the thread yourself. The BackgroundWorker.RunWorkerAsync method is a prime example. You call the method and then the thread that called it continues on to the next line of code. In the background a thread pool thread is used to raise the DoWork event, thus the DoWork event handler gets executed on that background thread.
-
2 Attachment(s)
Re: [2008] retrieving bytes for progress bar
ok thanks thats helped sum it up.
Ive just used jmcihineys's code but for some reason, when it runs half the window disapears! I have the progress bar in a statusstrip at the bottom.
The download doesnt download
any ideas?
pics are attached
if u need my project file ill upload it for you
-
Re: [2008] retrieving bytes for progress bar
-
Re: [2008] retrieving bytes for progress bar
ok heres my entire code block;
Code:
Imports System.Net
Imports System.IO
Imports System.IO.FileInfo
Imports System.Text
Imports System.ComponentModel
Public Class Form1
Private WithEvents wc As New Net.WebClient
Private filePath As String = "http://wiikey.elementfx.com/Firmware/" & listbox
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim fwr As FtpWebRequest = FtpWebRequest.Create("ftp://wiikey.elementfx.com/www/Firmware/")
fwr.Timeout() = "60000"
fwr.Credentials = New NetworkCredential("wiikey", "colin123")
fwr.Method = WebRequestMethods.Ftp.ListDirectory
Dim sr As New StreamReader(fwr.GetResponse().GetResponseStream())
Dim str As String
str = sr.ReadLine()
ListBox1.Items.Clear()
While Not str Is Nothing
ListBox1.Items.Add(str)
ListBox1.Items.Remove(".")
ListBox1.Items.Remove("..")
str = sr.ReadLine()
End While
sr.Close()
StatusLBL.Text = "Ready"
Button1.Text = "Refresh"
sr = Nothing
fwr = Nothing
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Me.MaximumSize = New Size(599, 336)
'Me.MinimumSize = New Size(599, 336)
listbox = ListBox1.SelectedItem
DownloadDirectoryOverall = DownloadDirectory & ListBox1.SelectedItem
Downloadtxtbox.Text = Environment.SpecialFolder.Desktop
DownloadDirectory = Downloadtxtbox.Text
End Sub
Private Sub ToolStripStatusLabel1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StatusLBL.Click
End Sub
Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseDown
StatusLBL.Text = "Connecting"
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
DownloadDirectoryOverall = DownloadDirectory & ListBox1.SelectedItem
DownloadButton.Enabled = True
If My.Computer.FileSystem.FileExists(DownloadDirectoryOverall & ".txt") = False Then
Dim client As New WebClient()
'client.Credentials = New NetworkCredential("wiikey", "colin123")
StatusLBL.Text = "Downloading Details..."
client.DownloadFile("http://wiikey.elementfx.com/readmes/" & ListBox1.SelectedItem & ".txt", DownloadDirectoryOverall & ".txt")
Dim myStreamReader As StreamReader
myStreamReader = File.OpenText(DownloadDirectoryOverall & ".txt")
TextBox1.Text = myStreamReader.ReadToEnd()
If Not myStreamReader Is Nothing Then
myStreamReader.Close()
End If
StatusLBL.Text = "Ready"
Else
If My.Computer.FileSystem.DirectoryExists(DownloadDirectory) = True Then
Dim myStreamReader As StreamReader
myStreamReader = File.OpenText(DownloadDirectoryOverall & ".txt")
TextBox1.Text = myStreamReader.ReadToEnd()
If Not myStreamReader Is Nothing Then
myStreamReader.Close()
End If
Else
MessageBox.Show("Please choose a download folder that exists")
End If
End If
End Sub
Private Sub DownloadButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownloadButton.Click
listbox = ListBox1.SelectedItem
If DownloadButton.Text = "Cancel" = False Then
If My.Computer.FileSystem.FileExists(DownloadDirectoryOverall) = True Then
StatusLBL.Text = "Firmware Already Downloaded"
Else
If My.Computer.FileSystem.DirectoryExists(DownloadDirectory) = True Then
Me.wc.DownloadFileAsync(New Uri(Me.filePath), _
IO.Path.Combine(DownloadDirectory, _
IO.Path.GetFileName(Me.filePath)))
'StatusLBL.Text = statuslblall
'With BackgroundWorker1
' .WorkerReportsProgress = True
' .WorkerSupportsCancellation = True
' .RunWorkerAsync(statuslblall)
' DownloadButton.Text = "Cancel"
'' StatusLBL.Text = "Downloading Firmware...Please Wait"
'End With
End If
End If
Else
Me.wc.CancelAsync()
End If
End Sub
Private Sub wc_DownloadFileCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted
If e.Error Is Nothing Then
Me.StatusLBL.Text = "Download Complete"
Else
Me.StatusLBL.Text = e.Error.ToString()
End If
End Sub
Private Sub wc_DownloadProgressChanged(ByVal sender As Object, _
ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.ProgressBar1.Maximum = CInt(e.TotalBytesToReceive)
Me.ProgressBar1.Value = CInt(e.BytesReceived)
Me.StatusLBL.Text = e.ProgressPercentage & "% Complete"
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
With FolderBrowserDialog1
' Desktop is the root folder in the dialog.
.RootFolder = Environment.SpecialFolder.Desktop
' Select the C:\Windows directory on entry.
.SelectedPath = Environment.SpecialFolder.MyDocuments
' Prompt the user with a custom message.
.Description = "Select the source directory"
If .ShowDialog = DialogResult.OK Then
' Display the selected folder if the user clicked on the OK button.
Downloadtxtbox.Text = .SelectedPath
DownloadDirectory = Downloadtxtbox.Text
DownloadDirectoryOverall = DownloadDirectory & ListBox1.SelectedItem
End If
End With
End Sub
Private Sub Downloadtxtbox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Downloadtxtbox.TextChanged
End Sub
Private Sub ComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox.SelectedIndexChanged
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
'For i As Integer = 1 To 100
' 'Raise the ProgressChanged event in the UI thread.
' worker.ReportProgress(i, i & " iterations complete")
' client.DownloadFile("http://wiikey.elementfx.com/Firmware/" & listbox, DownloadDirectoryOverall)
' ''Perform some time-consuming operation here.
' 'Threading.Thread.Sleep(250)
'Next i
'client.Credentials = New NetworkCredential("wiikey", "colin123")
'client.DownloadFile("http://wiikey.elementfx.com/Firmware/" & listbox, DownloadDirectoryOverall)
'Call My.Computer.Network.DownloadFile("http://wiikey.elementfx.com/Firmware/" & listbox, DownloadDirectoryOverall)
End Sub
Private Sub ToolStripProgressBar1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ProgressBar1.Click
End Sub
Private Sub BackgroundWorker2_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
End Sub
End Class
your code starts iunder downloadbutton_click
-
Re: [2008] retrieving bytes for progress bar
your code starts iunder downloadbutton 1
-
Re: [2008] retrieving bytes for progress bar
right, ok i will try and make this a bit clearer.
here is my project file that should help, i would greatly appreciate someone taking a look at it. I just cant get my head round it. I think it could be the status label filling with blank info, but then the download doesnt start either.
http://rapidshare.com/files/11265911...downloader.zip
rapidshare happy hours are on so no waiting needed.
thanks!
-
Re: [2008] retrieving bytes for progress bar
ok ive jst found out that for some reason it executes the filecompleted part streight after initiating the download, and then trys to display an error. in the statuslbl. the code is identical to the one provided .
-
Re: [2008] retrieving bytes for progress bar
yesssss got it working, after all that it was just an undefined string, could have given me an error or something :S
-
Re: [2008] retrieving bytes for progress bar
Hmm...how do you get the file name and the download speed? With this you can get only received bytes, progress percentage and total bytes to receive or am I blind?
-
Re: [2008] retrieving bytes for progress bar
Private Sub wc_DownloadProgressChanged(ByVal sender As Object, _
ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.ProgressBar1.Maximum = CInt(e.TotalBytesToReceive)
Me.ProgressBar1.Value = CInt(e.BytesReceived)
Me.StatusLBL.Text = e.ProgressPercentage & "% Complete"
End Sub
like that, dunno about the speed, i would like to know though
-
Re: [2008] retrieving bytes for progress bar
How is speed always calculated? Distance divided by time. You need to determine the number of bytes received since the last event and the time since the last event, then divide them.
vb.net Code:
Private byteCount As Long
Private timer As Stopwatch
Private Sub wc_DownloadProgressChanged(ByVal sender As Object, _
ByVal e As Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged
Me.ProgressBar1.Maximum = CInt(e.TotalBytesToReceive)
Me.ProgressBar1.Value = CInt(e.BytesReceived)
Dim bits As Long = (e.BytesReceived - Me.byteCount) * 8
Dim seconds As Double = Me.timer.Elapsed.TotalSeconds
Dim speed As Integer = CInt(bits / seconds)
Me.StatusLBL.Text = e.ProgressPercentage & "% Complete (" & speed & " bps)"
Me.byteCount = e.BytesReceived
Me.timer = Stopwatch.StartNew()
End Sub
That's the most accurate current speed calculation possible under the circumstances. If you want average speed then you'd calculate the total number of bytes received and the total time taken.
-
Re: [2008] retrieving bytes for progress bar
It didnt work...=(
At the:
Dim seconds As Double = timer.Elapsed.TotalSeconds
it showed error when I try to download.
-
Re: [2008] retrieving bytes for progress bar
Quote:
Originally Posted by nanoman
It didnt work...=(
At the:
Dim seconds As Double = timer.Elapsed.TotalSeconds
it showed error when I try to download.
Did you create a Stopwatch when you started the download in the first place? You can't get the Elapsed property value of a Stopwatch that doesn't exist.
-
Re: [2008] retrieving bytes for progress bar
Thanks...lolz, I thought that it is already running cause I see:
Me.timer = Stopwatch.StartNew()
at the end of the DownloadProgressChanged.
But the speed is running like crazy, how to make it reload every 2 second?
Do I need to use the Timer?
-
Re: [2008] retrieving bytes for progress bar
Yes, a new StopWatch is created at the end of each DownloadProgressChanged event handler, but that is to measure the time elapsed until the next event. You still need to create a Stopwatch when you initiate the download to measure the time elapsed until the first DownloadProgressChanged event.
A Timer's not going to be any use because you only get byte counts in the DownloadProgessChanged event handlers. If you don't want to update the speed every time then don't. Just keep a counter and only update the speed every second time, or every third time or whatever.
-
Re: [2008] retrieving bytes for progress bar
ok for some reason when using this code i get a target invocation exeption. this occurs at dim bits as long
why is this, ive studied it over and over again and nothing seems wrong to me.
any ideas?
-
Re: [2008] retrieving bytes for progress bar
I just wrote that code off the top of my head so I haven't tested it. If and when I get a chance I'll run it myself and see what happens but I can't make any promises about when that will be.