Overload VB.NET event? - vb.net

In my VB.NET class I have some code like this:
Public Class barClass
Private Function foo(data as string)
msgbox("Data is a string: " & data)
End Function
Private Function foo(data as integer)
msgbox("Data is an integer: " & data
End Function
End Class
Which obviously lets you pass foo a string or integer.
I figured I could do the same for events, so I try:
Public Event FooRaised(data as string)
Public Event FooRaised(data as integer)
Which I assume would let me raise the event by passing it whatever data I get from foo but I get an error, saying I can't do that (that FooRaised has already been declared).
How do I achieve this?

Declare a single event using an Object parameter, then check the type to process it:
Public Class Form1
Public Event Foo(o As Object)
Sub FooHandler(o As Object) Handles Me.Foo
If o.GetType Is GetType(Integer) Then
Dim i As Integer = DirectCast(o, Integer)
i += 1 'add one to the integer value'
MsgBox(i.ToString)
ElseIf o.GetType Is GetType(String) Then
Dim s As String = DirectCast(o, String)
s &= "!!" 'append exclamation marks'
MsgBox(s)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
RaiseEvent Foo(21)
RaiseEvent Foo("a string value")
End Sub
End Class

Related

Looping through Playlist

I am having trouble looping through my playlist of mp3 tracks.
Can anybody shed some light on where I am going wrong. This is the code. It play the first track, but then stops.
Code has been edited 011020
' The following Menu Item plays the full list of mp3s in the list box
Private Sub PlayListToolStripMenuItem_Click(sender As Object, e As EventArgs)
Handles PlayListToolStripMenuItem.Click
FromDictionary = False
PlaySongsFromListBox()
End Sub
Private Sub PlaySongsFromListBox()
'MsgBox("Index Counter = " & NextIndex)
'MsgBox("Total No of Tracks = " & ListBox1.Items.Count)
If NextIndex = ListBox1.Items.Count Then
NextIndex = 0
MessageBox.Show("All music has been played")
Exit Sub
End If
Dim item As KeyValuePair(Of String, String) =
DirectCast(ListBox1.Items(NextIndex), KeyValuePair(Of String, String))
Dim SongPath = Path.Combine(item.Value, item.Key)
PlayASong(SongPath)
End Sub
Private Sub PlayASong(SongPath As String)
MsgBox("Playing Track: " & SongPath)
CurrentMediaStreamName = SongPath
MediaPlayer1.URL = SongPath
MediaPlayer1.Ctlcontrols.play()
MsgBox("Playing Track: " & SongPath)
End Sub
Private Sub MediaPlayer1_PlayStateChange(sender As Object, e As
AxWMPLib._WMPOCXEvents_PlayStateChangeEvent) Handles
MediaPlayer1.PlayStateChange
If MediaPlayer1.playState = WMPLib.WMPPlayState.wmppsMediaEnded Then
NextIndex += 1
PlaySongsFromListBox()
End If
End Sub
At the class level (Form1) I declared 4 variables that are used in more than one method.
In the Form.Load I filled the MusicDictionary. You may be filling this from a database or text file. I also bound the ListBox to the dictionary. The ListBox.DataSource cannot take a Dictionary directly but a BindingSource can handle it.
PlayASong simply does what it says.
PlaySongsFromDictionary first checks if we have come to the end of the Dictionary. Note that I reset NextIndex back to 0. I used Path.Combine to get the path for the song. Notice that in one dictionary entry, I left out a back slash at the end of the directories and in the other entry I included the backslash. Path.Combine accepted both and added a back slash where necessary. Also notice that the index is applied to the Keys collection and the Values collection of the Dictionary not the Dictionary itself. If we tried to apply the index to the dictionary it would be trying to look for the Key inside the brackets. Default Public Property Item(key As TKey) As TValue
PlaySongsFromListBox casts the list box item (which is an object) back to its underlying type, KeyValuePair.
Finally, the important part! I used the MediaEnded event of the MediaPlayer1 to determine when to play the next song. Here I incremented the index and called the one of the PlaySongs... methods.
Private NextIndex As Integer
Private WithEvents MediaPlayer1 As New MediaPlayer
Private MusicDictionary As New Dictionary(Of String, String)
Private FromDictionary As Boolean
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MusicDictionary.Add("2018-11-27_-_Track_A_-_FesliyanStudios.com_By_Stephen_Bennett.mp3", "C:\Users\maryo\Documents\Marys Music")
MusicDictionary.Add("file_example_MP3_700KB.mp3", "C:\Users\maryo\Documents\Marys Music\")
ListBox1.DataSource = New BindingSource(MusicDictionary, Nothing)
ListBox1.DisplayMember = "Key"
ListBox1.ValueMember = "Value"
End Sub
Private Sub PlayASong(SongPath As String)
MediaPlayer1.Open(New Uri(SongPath))
MediaPlayer1.Play()
End Sub
Private Sub PlaySongsFromDictionary()
If NextIndex = MusicDictionary.Count Then
NextIndex = 0
MessageBox.Show("All music has been played")
Exit Sub
End If
Dim SongPath = Path.Combine(MusicDictionary.Values(NextIndex), MusicDictionary.Keys(NextIndex))
PlayASong(SongPath)
End Sub
Private Sub PlaySongsFromListBox()
If NextIndex = ListBox1.SelectedItems.Count Then
NextIndex = 0
MessageBox.Show("All music has been played")
Exit Sub
End If
Dim item As KeyValuePair(Of String, String) = DirectCast(ListBox1.SelectedItems(NextIndex), KeyValuePair(Of String, String))
Dim SongPath = Path.Combine(item.Value, item.Key)
PlayASong(SongPath)
End Sub
Public Sub MediaPlayers1_MediaEnded() Handles MediaPlayer1.MediaEnded
NextIndex += 1
If FromDictionary Then
PlaySongsFromDictionary()
Else
PlaySongsFromListBox()
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
FromDictionary = False
PlaySongsFromListBox()
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
FromDictionary = True
PlaySongsFromDictionary()
End Sub
The problem with the MP3's not looping was solved using the following invoke method
If e.newState = WMPLib.WMPPlayState.wmppsStopped Then
Me.BeginInvoke(New Action(AddressOf NextSong))
End If
Found at the following location Function call only works when MessageBox.Show() is included?

Display variable content dynamically

I'm trying to do this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim my_variable as String = "hello"
Dim blabla as string = "my_variable"
msgbox(blabla) ' I want this to display: "hello"
End Sub
Any way you guys can help me in VB.NET (not C# please).
What you want cannot be done for a LOCAL variable like my_variable.
If that variable is at CLASS level, though, it can be done with REFLECTION.
If the variable is at class level and is PUBLIC, you can cheat and use CallByName:
Public Class Form1
Public counter As Integer = 911
Public my_variable As String = "Hello World!"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim variable As String = TextBox1.Text
Try
Dim value As String = CallByName(Me, variable, CallType.Get)
MessageBox.Show(variable & " = " & value)
Catch ex As Exception
MessageBox.Show("Variable not found: " & variable)
End Try
End Sub
End Class
Type the name of the variable in TextBox1 and its value will be displayed in the message box....easy peasy.
If you don't want the variables to be public, then it can be accomplished via Reflection, but it doesn't look quite as simple and pretty. Look it up if you want to go that route.
--- EDIT ---
Here's a version that can find public members of a module:
Code:
Imports System.Reflection
Public Class Form2
Public counter As Integer = 911
Public my_variable As String = "Hello World!"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lblResults.Text = ""
Dim variable As String = TextBox1.Text
Try
Dim value As String = CallByName(Me, variable, CallType.Get)
lblResults.Text = variable & " = " & value
Catch ex As Exception
End Try
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
lblResults.Text = ""
Dim moduleName As String = txtModule.Text
Dim moduleField As String = txtModuleMember.Text
Dim myType As Type = Nothing
Dim myModule As [Module] = Nothing
For Each x In Assembly.GetExecutingAssembly().GetModules
For Each y In x.GetTypes
If y.Name.ToUpper = moduleName.ToUpper Then
myType = y
Exit For
End If
Next
If Not IsNothing(myType) Then
Exit For
End If
Next
If Not IsNothing(myType) Then
Dim flags As BindingFlags = BindingFlags.IgnoreCase Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static Or BindingFlags.Instance
Dim fi As FieldInfo = myType.GetField(moduleField, flags)
If Not IsNothing(fi) Then
Dim value As String = fi.GetValue(Nothing)
lblResults.Text = moduleField & " = " & value
End If
End If
End Sub
End Class
Public Module PutThings
Public SomeValue As String = "...success!..."
End Module
My suggestion (just 1 idea, thinking out loud) would be to create a separate, global list of all of your variables, and every single time one of the variables you want to know the contents of changes, update the global list.
For example:
' Global declaration
Dim dictionary As New Dictionary(Of String, String)
Sub Form_Load()
' Add keys to all vars you want to lookup later
With dictionary
.Add("varCarrot", String.Empty)
.Add("varPerl", String.Empty)
End With
End Sub
Sub SomeSub()
strCarrot = "hello"
intPerl = 12
' Any time the vars change that you want to track, update the respective dictionary key
dictionary(varCarrot) = strCarrot
dictionary(varPerl) = intPerl.ToString
Do Until intPerl = 100
intPerl += 1
strCarrot = "hello " & intPerl
dictionary(varCarrot) = strCarrot
dictionary(varPerl) = intPerl.ToString
Loop
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
dim strLookup as String = text1.text ' the variable you want to lookup entered in the text1 textbox; i.e. "varCarrot"
' See if the requested key exists
If dictionary.ContainsKey(strLookup) Then messagebox.show(dictionary.Item(strLookup))
End Sub
When you're ready to no longer have that functionality in your app, such as when all done debugging it, and ready to finally release it, comment out all the dictionary stuff.

Multithreading duplicate error after background worker added

I wrote a program that does queries on some search engines that I wanted to be multithreaded so it could do the searches faster. I made a question about this which was answered indirectly, but I have yet another problem even after I set up delegates and such.
I was running the queries on the main thread, so I had to set up a BackgroundWorker. I did that but even though everything seems to run without an issue, I get duplicates of my results even though the program is suppose to do the opposite. Sometimes it doesn't even read or output a result that I know would be good.
Imports System.Net
Imports System.IO
Imports System.ComponentModel
Public Class Form2
Dim i As Integer
Dim SearchString As String
Public CleanSearchStrings As String()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
i = RichTextBox1.Lines.Count
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub StartThreads()
While i > 0
i = i - 1
Dim thread_count As String = Process.GetCurrentProcess().Threads.Count - 20
Label_T(thread_count)
SearchString = LineFunc(i)
Threading.Thread.Sleep(500)
SearchString = Ask_Query(SearchString) #This was commented out
SearchString = Bing_Query(SearchString) #just simple webscraping
SearchString = Yahoo_Query(SearchString)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
End While
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Private Delegate Function Line(ByVal i As Integer)
Function LineFunc(ByVal i As Integer)
If Me.InvokeRequired Then
Me.Invoke(New Line(AddressOf LineFunc), New Object() {i})
Else
SearchString = RichTextBox1.Lines(i).ToString
Return SearchString
End If
End Function
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " + thread_count
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.WorkerReportsProgress = True
Dim count As Integer
Dim num As Integer = TextBox1.Text - 1
For count = 0 To num
Dim thread = New Threading.Thread(AddressOf StartThreads)
thread.IsBackground = True
thread.Start()
Threading.Thread.Sleep(500)
Next
End Sub
End Class
I know it has something to do with the LineFunc that I wrote but I can't seem to figure it out.
This was working flawlessly on multithreading, but the UI would be frozen and after I added the BackgroundWorker it seems to be giving me these duplicate results error and not reading the TextBox fully.
Update:
Private Sub StartThreads()
For count = count To i
Dim SearchString As String = LineFunc(count)
count += 1
Dim thread_count As String = CType(Process.GetCurrentProcess().Threads.Count - 20, String)
Label_T(thread_count)
Threading.Thread.Sleep(500)
SearchString = CType(Ask_Query(SearchString), String)
SearchString = CType(Bing_Query(SearchString), String)
SearchString = CType(Yahoo_Query(SearchString), String)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
Next
End Sub
Heres my Revised Get Line Func
Private Delegate Function GetTextBox(ByVal index As Integer) As String
Public Function LineFunc(ByVal index As Integer) As String
If Me.InvokeRequired Then
Me.Invoke(New GetTextBox(AddressOf LineFunc), New Object() {index})
Else
Dim indexSearchString As String
indexSearchString = CType(RichTextBox1.Lines(index), String)
Return indexSearchString
End If
End Function
If i use the a msgbox it gives me the right values i don't understand how come it does not give me the right values when i do the func Dim SearchString As String = LineFunc(count) it returns a null string in the end i don't understand why
this seemed to work for the duplicate issue but now i seem to be having issues with my output to richtextbox2 only outputing blanks and the line func is only giving out blanks i don't understand why either but atleast there is progress
I can't verify if this will work as you haven't posted the search functions, but here goes.
Public Class Form2
Dim i As Integer
Dim SearchString As String
Dim ResultString As String
Public CleanSearchStrings As String()
Private threadCount As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SearchUsingRTB1Items()
End Sub
Private Sub SearchUsingRTB1Items()
threadCount = 0
Dim rtb1Lines() As String = RichTextBox1.Lines
Parallel.ForEach(rtb1Lines, Sub(line As String)
dim ResultString As String =""
threadCount += 1
Label_T(i.ToString)
ResultString =Ask_Query(line) 'This was commented out
ResultString = ResultString & Bing_Query(line) 'just simple webscraping
ResultString = ResultString & Yahoo_Query(line)
If ResultString.Contains("All_Query:Yes") Then
ResultString = ResultString.Replace("All_Query:Yes", "")
RTB(ResultString)
End If
threadCount -= 1
Label_T(i.ToString)
End Sub)
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " & thread_count
End If
End Sub
End Class

CSV file to datagridview using list

This is similar to:
https://social.msdn.microsoft.com/Forums/en-US/7b0e28b4-c1ef-49d6-8f46-11b379428052/import-from-csv-file-to-two-dimensional-array?forum=vbgeneral
but the code that Cor Ligthert suggests doesn't work even though its exactly what I need.
The code is:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim FILE_NAME As String = "C:\Users\Admin\Documents\test.csv"
Dim OutlookLines As New List(Of OutlookLine)
Dim sr As New IO.StreamReader(FILE_NAME)
Do Until sr.EndOfStream
OutlookLines.Add(New OutlookLine With {.line = sr.ReadLine})
Loop
DataGridView1.DataSource = OutlookLines
End Sub
Private Class OutlookLine
Private theLine As String
Public Property line() As String
Get
Return theLine
End Get
Set(ByVal value As String)
theLine = value
End Set
End Property
End Class
End Class
I try putting in:
.Split(","c)
after sr.ReadLine but it says "Value of type 1-D array of String cannot be converted to String"
The code above works fine but each row of the csv is scrunched into one column (obviously because I am not splitting it at the ",").
csv data:
1,2,3,4,5
6,7,8,9,0
See if this works for you:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DataGridView1.DataSource = CSVToDataTable("C:\Users\Admin\Documents\test.csv", True)
End Sub
Private Function CSVToDataTable(filePath As String, Optional hasHeaderRow As Boolean = False) As DataTable
Dim rows = IO.File.ReadAllLines(filePath).Select(Function(l) l.Split(","c))
Dim dt = New DataTable
Dim count = 0
dt.Columns.AddRange(rows.First.Select(Function(c) New DataColumn With {.ColumnName = If(hasHeaderRow, c, "Column" & Threading.Interlocked.Increment(count))}).ToArray())
For Each row In rows.Skip(If(hasHeaderRow, 1, 0))
Dim dr = dt.NewRow()
dr.ItemArray = row
dt.Rows.Add(dr)
Next
Return dt
End Function
If you wish for the line property of the OutlookLine class to be an array of string, you should define it like this:
Private Class OutlookLine
Private theLine As String()
Public Property line As String()
Get
Return theLine
End Get
Set(ByVal value As String())
theLine = value
End Set
End Property
End Class
Then this will work:
OutlookLines.Add(New OutlookLine With {.line = sr.ReadLine.Split(",")})

Conversion from string "" to type 'Double' is not valid using TryParse Method

I have a simple addition program in VB.Net and I am attempting to test if the textbox is only taking in a number and not any letters. I need to use the TryParse method, and I cannot figure out wny I am still receiving this error. Pls Help
Public Class perrySolutionForm
Dim numberOne As Double
Dim numberTwo As Double
Public Function sum(ByRef numberOne As Double, ByRef numberTwo As Double)
sum = Val(numberOne) + Val(numberTwo)
End Function
Public Function difference(ByRef numberOne As Double, numberTwo As Double)
difference = Val(numberOne) - Val(numberTwo)
End Function
Private Sub sumButton_Click(sender As Object, e As EventArgs) Handles sumButton.Click
If numberOneInput.Text = "" Then
MessageBox.Show("Both fields must be filled out.")
If Double.TryParse(numberOneInput.Text, numberOne) Then
MessageBox.Show("Success")
'numberOne has a Double value
Else
MessageBox.Show("Failure")
'numberOne = Nothing
End If
Else
outputLabel.Text = sum(numberOne, numberTwo)
End If
End Sub
Private Sub numberOneInput_TextChanged(sender As Object, e As EventArgs) Handles numberOneInput.TextChanged
numberOne = numberOneInput.Text
End Sub
Private Sub numberTwoInput_TextChanged(sender As Object, e As EventArgs) Handles numberTwoInput.TextChanged
numberTwo = numberTwoInput.Text
End Sub
This is how you use the TryParse:
If Double.TryParse(numberOneInput.Text, numberOne) Then
'code for a success
'numberOne has a Double value
Else
'code for a failure
'numberOne = Nothing
End If
End the code block if text is empty:
If String.IsNullOrWhiteSpace(numberOneInput.Text) Then
MessageBox.Show("Value is incorrect format")
Exit Sub
End If