VB.net link extraction with HtmlAgilityPack - vb.net

I was able to extract URLs with simple href tags like this:
<a href="http://www.samplesite.com">
but my problem is how do i extract a link from an href tag that looks like this?
<a href="http://www.wherecreativitygoestoschool.com/vancouver/left_right/rb_test.htm" onmousedown="return rwt(this,'','','','1','AFQjCNHvlwTxfBVEYcqGUnilAZN0uY2IXw','','0CCsQFjAA','','',event)">
Right Brain vs Left Brain Creativity <em>Test</em> at The Art Institute of <b>...</b></a>
Here is my complete code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim webClient As New System.Net.WebClient
Dim WebSource As String = webClient.DownloadString("http://www.google.com.ph/search?hl=en&as_q=test&as_epq=&as_oq=&as_eq=&as_nlo=&as_nhi=&lr=&cr=countryCA&as_qdr=all&as_sitesearch=&as_occt=any&safe=images&tbs=ctr%3AcountryCA&as_filetype=&as_rights=#as_qdr=all&cr=countryCA&fp=1&hl=en&lr=&q=test&start=20&tbs=ctr:countryCA")
Dim doc = New HtmlAgilityPack.HtmlDocument()
doc.LoadHtml(WebSource)
Dim links = GetLinks(doc, "test")
For Each Link In links
ListBox1.Items.Add(Link.ToString())
Next
End Sub
Public Class Link
Public Sub New(Uri As Uri, Text As String)
Me.Uri = Uri
Me.Text = Text
End Sub
Public Property Text As String
Public Property Uri As Uri
Public Overrides Function ToString() As String
Return String.Format(If(Uri Is Nothing, "", Uri.ToString()))
End Function
End Class
Public Function GetLinks(doc As HtmlAgilityPack.HtmlDocument, linkContains As String) As List(Of Link)
Dim uri As Uri = Nothing
Dim linksOnPage = From link In doc.DocumentNode.Descendants()
Where link.Name = "a" _
AndAlso link.Attributes("href") IsNot Nothing _
Let text = link.InnerText.Trim()
Let url = link.Attributes("href").Value
Where url.IndexOf(linkContains, StringComparison.OrdinalIgnoreCase) >= 0 _
AndAlso uri.TryCreate(url, UriKind.Absolute, uri)
Dim Uris As New List(Of Link)()
For Each link In linksOnPage
Uris.Add(New Link(New Uri(link.url, UriKind.Absolute), link.text))
Next
Return Uris
End Function
I have noticed that my code does not extract links that ends with </a>. Is there anything i can do to modify my code that it would extract links ending with </a>?

Use following code to grab all of links having 'href' attribute from page:
Dim hNodeCol as HTMLNodeCollection = doc.DocumentNode.SelectNodes("//a[#href]")
...if you still need it, ofcourse ;)

Related

Async download function, how to do it? VB.NET

I am working on coronavirus statistics dashboard as university project, and I have some problems with asynchronous source data download from sites with statistics.
Well, I failed to understand how to do it myself.
I tried to create my own class with function what will create multiple async web requests
and then wait until they all finished, then return results of all these requests.
Imports System.Net.WebClient
Imports System.Net
Public Class AsyncDownload
Private result As New Collection
Private Sub DownloadCompletedHander(ByVal sender As Object, ByVal e As System.Net.DownloadStringCompletedEventArgs)
If e.Cancelled = False AndAlso e.Error Is Nothing Then
Dim myString As String = CStr(e.Result)
result.Add(myString, sender.Headers.Item("source"))
End If
End Sub
Public Function Load(sources As Array, keys As Array) As Collection
Dim i = 0
Dim WebClients As New Collection
While (i < sources.Length)
Dim newClient As New WebClient
newClient.Headers.Add("source", keys(i))
newClient.Headers.Add("sourceURL", sources(i))
AddHandler newClient.DownloadStringCompleted, AddressOf DownloadCompletedHander
WebClients.Add(newClient)
i = i + 1
End While
i = 1
For Each client As WebClient In WebClients
Dim url As String = client.Headers.Item("sourceURL")
client.DownloadStringAsync(New Uri(url))
Next
While (result.Count < WebClients.Count)
End While
Return result
End Function
End Class
And it is used in:
Dim result As New Collection
Private Sub test() Handles Me.Load
Dim downloader As New CoronaStatisticsGetter.AsyncDownload
result = downloader.Load({"https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_total.json"}, {"Nationalwide Data"})
End Sub
It should work like:
I create a new instance of my class.
Calling function Load of this class
Funciton Load creates instances of System.Net.WebClient for each url and adds as handler DownloadCompletedHander
Function Load goes calls DownloadStringAsync of each client
Function Load waits in While loop until result collection items count is not as big as number of url on input
If item count in result is same as urls number that means what everything is downloaded, so it breaks loop and returns all requested data
The problem is that it doesn't work, it just endlessly remain in while loop, and as I see using debug collection result is not updated (its size is always 0)
Same time, when I try to asynchronously download it without using my class, everything works fine:
Private Sub Download() 'Handles Me.Load
Dim wc As New System.Net.WebClient
wc.Headers.Add("source", "VaccinationByAgeGroup")
AddHandler wc.DownloadStringCompleted, AddressOf DownloadCompletedHander
wc.DownloadStringAsync(New Uri("https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_agegroup.json"))
End Sub
Could somebody tell me please why it is not working and where is the problem?
The following shows how one can use System.Net.WebClient with Task to download a string (ie: data) from a URL.
Add a project reference (System.Net)
VS 2019:
In VS menu, click Project
Select Add reference...
Select Assemblies
Check System.Net
Click OK
Create a class (name: DownloadedData.vb)
Public Class DownloadedData
Public Property Data As String
Public Property Url As String
End Class
Create a class (name: HelperWebClient.vb)
Public Class HelperWebClient
Public Async Function DownloadDataAsync(urls As List(Of String)) As Task(Of List(Of DownloadedData))
Dim allTasks As List(Of Task) = New List(Of Task)
Dim downloadedDataList As List(Of DownloadedData) = New List(Of DownloadedData)
For i As Integer = 0 To urls.Count - 1
'set value
Dim url As String = urls(i)
Debug.WriteLine(String.Format("[{0}]: Adding {1}", i, url))
Dim t = Task.Run(Async Function()
'create new instance
Dim wc As WebClient = New WebClient()
'await download
Dim result = Await wc.DownloadStringTaskAsync(url)
Debug.WriteLine(url & " download complete")
'ToDo: add desired code
'add
downloadedDataList.Add(New DownloadedData() With {.Url = url, .Data = result})
End Function)
'add
allTasks.Add(t)
Next
For i As Integer = 0 To allTasks.Count - 1
'wait for a task to complete
Dim t = Await Task.WhenAny(allTasks)
'remove from List
allTasks.Remove(t)
'write data to file
'Note: The following is only for testing.
'The index in urls won't necessarily correspond to the filename below
Dim filename As String = System.IO.Path.Combine("C:\Temp", String.Format("CoronavirusData_{0:00}.txt", i))
System.IO.File.WriteAllText(filename, downloadedDataList(i).Data)
Debug.WriteLine($"[{i}]: Filename: {filename}")
Next
Debug.WriteLine("all tasks complete")
Return downloadedDataList
End Function
End Class
Usage:
Private Async Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
Dim helper As HelperWebClient = New HelperWebClient()
Dim urls As List(Of String) = New List(Of String)
urls.Add("https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_total.json")
urls.Add("https://api.covidtracking.com/v2/states.json")
urls.Add("https://covidtrackerapi.bsg.ox.ac.uk/api/v2/stringency/date-range/2020-01-01/2022-03-01")
urls.Add("http://covidsurvey.mit.edu:5000/query?age=20-30&gender=all&country=US&signal=locations_would_attend")
Dim downloadedDataList = Await helper.DownloadDataAsync(urls)
Debug.WriteLine("Complete")
End Sub
Resources:
How do I wait for something to finish in C#?
How should Task.Run call an async method in VB.NET?
VB.net ContinueWith

Utilizing wildcards and variables for getFiles

I am kinda new to VB.net, so I am not sure if I try this the right way. I have the following piece of code.
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Dim TextLine As String
Do While objReader.Peek() <> -1
Dim newString As String = TextLine.Replace(vbCr, "").Replace(vbLf, "") & ".wav"
Dim SongName As String = My.Computer.FileSystem.GetName(newString)
Dim MyFile As String = Dir("C:\AllSongs\" & newString)
Dim Searchquery As IEnumerable(Of String) = IO.Directory.EnumerateFiles("C:\AllSongs", "*", IO.SearchOption.AllDirectories).Where(Function(f) IO.Path.GetFileNameWithoutExtension(f).IndexOf(SongName, StringComparison.CurrentCultureIgnoreCase) >= 0)
For Each Result In Searchquery
ListBox1.Items.Add(Result)
Next
I am trying to use the lines in the text file, and get the .wav in AllSongs dir that partially correspond in these files. Can it be done?
Edit: Part of the code contains a media player. I want to be able to play songs from this player, by choosing files in the list.
Private Sub ListBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.DoubleClick
AxWindowsMediaPlayer1.URL = ListBox1.SelectedItem
Dim variables As New Dictionary(Of String, String)()
Dim selectedItem As Object = ListBox1.SelectedItem
variables("MyDynamicVariable") = selectedItem ' Set the value of the "variable"
selectedItem1 = selectedItem
Dim value As String = variables("MyDynamicVariable") ' Retrieve the value of the variable
End Sub
Incidental to the question, but important, is that when you're working with files it's often necessary to clean up some resources (file handles, I guess) that the operating system uses even though you don't see it directly in the code as written. There is a way of doing that automatically with the Using statement, as shown in the following code.
To find out if a filename contains some text (string), you can extract the filename with no path or extension with Path.GetFileNameWithoutExtension and check if it contains the desired string with the IndexOf function, which lets you ignore uppercase/lowercase by specifying how to do the check.
I notice from an update to the question that some improvements can be made, such as using a Class for the song entries so that the displayed list can have more information behind it, which means that the song name can be shown on its own but you can get the full path to the file when you click on it.
I made a new Windows Forms project and added just a ListBox to it, and used this code to show the full path (which you can use for your media player) to the song when its name is double-clicked:
Imports System.IO
Public Class Form1
Public Class SongEntry
Property Name As String
Property FullName As String
End Class
Sub PopulateSongList(musicDirectory As String, songsList As String)
Dim songList As New List(Of SongEntry)
Using sr As New System.IO.StreamReader(songsList)
Do While Not sr.EndOfStream
Dim thisSong = sr.ReadLine()
If thisSong <> "NaN" Then
Dim fs = Directory.EnumerateFiles(musicDirectory, "*.wav", SearchOption.AllDirectories).
Where(Function(f) Path.GetFileNameWithoutExtension(f).IndexOf(thisSong, StringComparison.CurrentCultureIgnoreCase) >= 0).
Select(Function(g) New SongEntry With {.Name = Path.GetFileNameWithoutExtension(g), .FullName = g})
songList.AddRange(fs)
End If
Loop
End Using
ListBox1.DataSource = songList
ListBox1.DisplayMember = "Name"
ListBox1.ValueMember = "FullName"
End Sub
Private Sub ListBox1_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick
Dim lb = DirectCast(sender, ListBox)
If lb.SelectedIndex >= 0 Then
Dim fullPathToSong = lb.SelectedValue.ToString()
MsgBox(fullPathToSong)
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim songsList = "C:\temp\AllSongs\songsList.txt"
Dim musicDirectory = "C:\temp\AllSongs"
PopulateSongList(musicDirectory, songsList)
End Sub
End Class

Value of type 'Uri()' cannot be converted to 'List(Of Uri)'

I am in visual studio 2015 visual basic (wich I think is what VB.net is) and getting this error:
BC30311 Value of type 'Uri()' cannot be converted to 'List(Of Uri)'
on this line 2 of this code:
Public Class Form1
Public Pages As List(Of Uri) = {New Uri("https://google.com/")}
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Searchbar.Text.Contains("http://") Or Searchbar.Text.Contains("https://") Then
WebBrowser1.Url = New Uri(Searchbar.Text)
Pages.Add(New Uri(Searchbar.Text))
Else
If Not Searchbar.Text.Equals("") Then
WebBrowser1.Url = New Uri("http://" & Searchbar.Text)
Pages.Add(New Uri("http://" & Searchbar.Text))
' Pages.Add(New Uri("http://" & Searchbar.Text))
End If
End If
End Sub
End Class
I haven't found anything on the internet that seems to be about this specific error, and I don't see how what I am doing is different from what is on this page. What am I doing wrong?
Edit: Thanks, it works now!
Your code for initializing the list are wrong. See the code below.
Public Pages As List(Of Uri) = New List(Of Uri)(New Uri() {
New Uri("https://google.com/"),
New Uri("https://amazon.com/")
})
Alternative code.
Public Pages As List(Of Uri) = New List(Of Uri) From {
New Uri("https://google.com/"),
New Uri("https://amazon.com/")
}
As Han said the initialization is incorrect. Here is another alternative
Public Pages As List(Of Uri) = {New Uri("https://google.com/"),
New Uri("http://www.vbforums.com/forumdisplay.php?25-Visual-Basic-NET/"),
New Uri("https://amazon.com/")}.ToList

function works when htmlDocument created inside function but not when htmlDocument created outside and passed as argument

Firstly here is my code:
Imports HtmlAgilityPack
Public Class Form1
Public Property myPage As HtmlDocument
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
myPage = OpenDoc(txtURL.Text)
'Dim myPage As HtmlDocument = OpenDoc(txtURL.Text)
Dim tmp = NameGroup(myPage)
Dim tmp1 = NextPage(myPage) 'txtURL.Text)
'Dim tmp2 = ProvinceLinks(myPage)
'Dim tmp3 = CityLinks(myPage)
End Sub
Public Function OpenDoc(ByVal url As String) As HtmlDocument
If (url Is Nothing) Then Throw New ArgumentNullException("url")
Dim web As New HtmlWeb()
Dim document As HtmlDocument = web.Load(url)
Return document
End Function
Public Function NameGroup(ByVal document As HtmlDocument) As List(Of String)
Dim myNameGroup As New List(Of String)
If (Not document.DocumentNode Is Nothing) Then
Dim rootNode As HtmlNode = document.DocumentNode.SelectSingleNode("//table")
If (Not rootNode Is Nothing) Then
document.LoadHtml(rootNode.InnerHtml())
If (Not document.DocumentNode Is Nothing) Then
Dim node As HtmlNodeCollection = document.DocumentNode.SelectNodes("//tr//td//p//a")
For Each n In node
'Dim myProvince = n.InnerText
Dim myUrl = n.GetAttributeValue("href", String.Empty)
If Not String.IsNullOrEmpty(myUrl) Then myNameGroup.Add("https://411.ca" & myUrl)
Next
Return myNameGroup
End If
End If
End If
Return Nothing
End Function
Public Function NextPage(document As HtmlDocument) As String 'url As String) As String '
Dim myNextPage As String = Nothing
'If (url Is Nothing) Then Throw New ArgumentNullException("url")
'Dim web As New HtmlWeb()
'Dim document As HtmlDocument = web.Load(url)
If (Not document.DocumentNode Is Nothing) Then
Dim rootNode As HtmlNode = document.DocumentNode.SelectSingleNode("//body")
If (Not rootNode Is Nothing) Then
document.LoadHtml(rootNode.InnerHtml())
If (Not document.DocumentNode Is Nothing) Then
Dim node As HtmlNode = document.DocumentNode.SelectSingleNode("//*[#class='pagination']")
myNextPage = node.ChildNodes("a").GetAttributeValue("href", String.Empty)
Return myNextPage
End If
End If
End If
Return Nothing
End Function
The Function OpenDoc works by providing an HTMLDocument object. This object is then used as an argument for other functions. This way the internet has to be accessed only once per URL.
This works fine for all but one function. My NextPage function will not work with this Function provided document object.
If you take a look at the NextPage function above you will see the same code, as in the OpenDoc function, commented out. When I uncomment this code and pass the URL the function works. When I comment the code and pass the myPage object argument to NextPage as either a property or as a local variable (you can see my comment mark next to the local variable), the NextPage function does not work.
The NextPage function passes it's "If (Not document.DocumentNode Is Nothing) Then" test but fails on the "If (Not rootNode Is Nothing) Then" test when I use the function provided HTMLDocument object.
The btnStart Sub is my Function Test sub. The commented out code is code that works. tmp and tmp1 share the same argument. tmp works and tmp1 does not.
I've tried to be as concise and provide as much information as possible without being redundant.
One would expect if it works for one it would work for all and visa versa. I'm not seeing the problem. Any ideas? If you need full code and URL let me know.
Thanks.
My NameGroup function was modifying the HTMLDocument.
When NameGroup runs the code
Dim rootNode As HtmlNode = document.DocumentNode.SelectSingleNode("//table")
Document.LoadHtml(rootNode.InnerHtml())
it changes the original Document value.
What I needed to do was to assign the RootNode to a new htmldocument variable.
eg.
Dim myDocument As New HtmlDocument
Dim rootNode As HtmlNode = document.DocumentNode.SelectSingleNode("//table")
myDocument.LoadHtml(rootNode.InnerHtml())
This leaves Document unchanged.

Insert string to <input> tag

I'm developing a client that connects to my server, and get access to download and upload files, and i seem to be stuck at uploading files. Here is my code on my VB.NET client:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Upload button
WebBrowser1.Visible = True
'Style OpenFileDialog1
OpenFileDialog1.Title = "Select file to upload"
OpenFileDialog1.InitialDirectory = System.Environment.SpecialFolder.Desktop
OpenFileDialog1.ShowDialog()
End Sub
Private Sub OpenFileDialog1_FileOk(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk
uploadFile = OpenFileDialog1.FileName.ToString()
If uploadFile = Nothing Then
MessageBox.Show("You just selected nothing.", "Information")
Else
WebBrowser1.Document.GetElementById("fileselect").SetAttribute("value", uploadFile)
WebBrowser1.Document.GetElementById("submit").InvokeMember("click")
End If
End Sub
And here is the HTML code:
<input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
<button type="submit" id="submit" class="uploadButton">Upload Files</button>
Also how do i make so that i can select multiple files? Via the web version you can select multiple files and it workes not not here?
So, as mentioned in the comments, input elements of type file do not allow for external modification, all interaction with them is done through the browser and is based on direct user interaction.
However, you could create an upload class that process the multiple file upload to your server, by creating a HttpWebRequest, which sends the data to the form. Provided there is no authentication, it can be done in the following way.
An interface that allows for some elementary actions for post data items
Public Interface IPostItem
ReadOnly Property Title As String
Property ElementName As String
Function GetPostData(inputNameElement As String) As String
End Interface
Some way to define the mime type of the file being sent
Public NotInheritable Class MimeTypeHandler
Private Shared ReadOnly images As String() = {"jpg", "gif", "bmp", "png", "jpeg"}
Public Shared Function GetMimeType(filename As String) As String
Dim extension As String = Path.GetExtension(filename).Replace(".", "")
If (images.Contains(extension)) Then
Return "image/" + extension
End If
Return "application/" + extension
End Function
End Class
Implement the IPostItem with an implementation that can post the file
Public Class FileQueueItem
Implements IPostItem
Public Property FileName As String
Public Property ElementName As String Implements IPostItem.ElementName
Public Function GetData() As Byte()
Dim result As Byte() = Nothing
Dim lengthRead As Integer = 0
Using stream As New FileStream(FileName, FileMode.Open, FileAccess.Read)
ReDim result(stream.Length)
lengthRead = stream.Read(result, 0, stream.Length)
End Using
Return result
End Function
Public ReadOnly Property ShortName As String Implements IPostItem.Title
Get
Return FileName.Substring(FileName.LastIndexOf("\") + 1)
End Get
End Property
Public ReadOnly Property MimeType As String
Get
Return MimeTypeHandler.GetMimeType(FileName)
End Get
End Property
Public Function GetPostData(inputNameElement As String) As String Implements IPostItem.GetPostData
Dim message As String = String.Empty
message += String.Format("Content-Disposition: form-data; name=""{0}""; filename=""{1}""{3}Content-Type: {2}{3}Content-Transfer-Encoding: base64{3}{3}", inputNameElement, ShortName, MimeType, Environment.NewLine)
message += Convert.ToBase64String(GetData())
Return message
End Function
Public Sub New(filename As String, elementName As String)
Me.FileName = filename
Me.ElementName = elementName
End Sub
End Class
Have a small controller class that runs the upload sequence using the BackgroundWorker class, it sends the files per 5 (can be set, is default value).
It requires a FormUrl, to say where the form is that is being posted to, in my case, i was running it on my localhost, so that you would see in the form code
Public Class FileUploader
Inherits BackgroundWorker
Private ReadOnly _listQueue As IList(Of IPostItem) = New List(Of IPostItem)
Public Property FormUrl As String
Public ReadOnly Property ListQueue As IList(Of IPostItem)
Get
Return _listQueue
End Get
End Property
Public Property MaxPerQueue As Integer
Protected Function HandleResponse(request As HttpWebRequest) As Boolean
Dim success As Boolean = False
Try
Using response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
success = response.StatusCode <> HttpStatusCode.OK
End Using
Catch ex As WebException
If ex.Response IsNot Nothing Then
ex.Response.Close()
End If
End Try
Return success
End Function
Protected Sub Run(sender As Object, e As DoWorkEventArgs)
If ListQueue.Count = 0 Then
' nothing to upload
Return
End If
' create the boundary string, used to split between the separate attachments
Dim boundary As String = String.Format("--------------------------{0}", DateTime.Now.Ticks)
Dim count As Integer = 0
Dim totalFiles As Integer = ListQueue.Count
Do
' create the request
Dim request As HttpWebRequest = CType(WebRequest.Create(Me.FormUrl), HttpWebRequest)
Dim fullPostMessage As String = String.Empty
request.AllowAutoRedirect = True
request.KeepAlive = True
request.Referer = Me.FormUrl
''// say that it has to post data
request.Method = WebRequestMethods.Http.Post
''// same style like a form
request.ContentType = "multipart/form-data;boundary=" + boundary
count = 0
Dim queueItem As IPostItem
While count < MaxPerQueue AndAlso ListQueue.Count > 0
''// get the item in the queue
queueItem = ListQueue(0)
''// report potential changes to gui
Report(queueItem.Title, count, totalFiles)
Dim postAsString As String = queueItem.GetPostData(queueItem.ElementName)
fullPostMessage &= String.Format("--{0}{1}{2}{1}", boundary, Environment.NewLine, postAsString)
''// remove the item from the queue
ListQueue.RemoveAt(0)
count += 1
End While
fullPostMessage &= "--" & boundary & "--"
Dim postData As Byte() = System.Text.Encoding.ASCII.GetBytes(fullPostMessage)
''// write data to the requestStream (post data)
request.ContentLength = postData.Length
Dim requestStream As Stream = request.GetRequestStream()
requestStream.Write(postData, 0, postData.Length)
requestStream.Close()
''// handle the response
HandleResponse(request)
requestStream.Dispose()
Loop While ListQueue.Count > 0
ListQueue.Clear()
Report("(Idle)", 0, 100)
End Sub
Protected Sub Report(filename As String, fileIndex As Integer, maxFiles As Integer)
Dim percentage As Integer = (fileIndex * 100) / maxFiles
ReportProgress(percentage, filename)
End Sub
Public Sub New()
Me.WorkerReportsProgress = True
AddHandler Me.DoWork, AddressOf Run
MaxPerQueue = 5
End Sub
End Class
Then you could create your form like this:
And then add the FileUploader class as a private member, so you can get notified when it has completed the upload stream, add the eventhandlers to get notified on the changes
Imports System.ComponentModel
Imports System.Net
Imports System.IO
Public Class Form1
Private fileUploadHandler As New FileUploader()
Private Sub btnUploadFiles_Click(sender As Object, e As EventArgs) Handles btnUploadFiles.Click
fileUploadHandler.FormUrl = "http://localhost:5555/Default.aspx"
Using openDialog As New OpenFileDialog
openDialog.Multiselect = True
openDialog.Title = "Select files to upload to the server"
If openDialog.ShowDialog() Then
' all files are selected
For Each fileName As String In openDialog.FileNames
Dim qItem As IPostItem = New FileQueueItem(fileName, "fileInfo[]")
fileUploadHandler.ListQueue.Add(qItem)
Next
btnUploadFiles.Enabled = False
fileUploadHandler.RunWorkerAsync()
End If
End Using
End Sub
Private Sub OnUploadCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
btnUploadFiles.Enabled = True
End Sub
Private Sub OnReportProgress(sender As Object, e As ProgressChangedEventArgs)
pbUploadProgress.Value = e.ProgressPercentage
lblUploadProgress.Text = e.UserState
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler fileUploadHandler.RunWorkerCompleted, AddressOf OnUploadCompleted
AddHandler fileUploadHandler.ProgressChanged, AddressOf OnReportProgress
End Sub
End Class
The files get then uploaded as soon as you click the Open button in the OpenFileDialog.
As to your second question, to allow for more than 1 file selected, you have to set the OpenFileDialog.Multiselect = True flag