Multiple Search Criteria (VB.NET) - vb.net

So my problem is:
I have a List of a custom Type {Id as Integer, Tag() as String},
and i want to perform a multiple-criteria search on it; eg:
SearchTags={"Document","HelloWorld"}
Results of the Search will be placed a ListBox (ListBox1) in this format:
resultItem.id & " - " & resultItem.tags
I already tried everything i could find on forums, but it didn't work for me (It was for db's or for string datatypes)
Now, i really need your help. Thanks in advance.
For Each MEntry As EntryType In MainList
For Each Entry In MEntry.getTags
For Each item As String In Split(TextBox1.Text, " ")
If Entry.Contains(item) Then
If TestIfItemExistsInListBox2(item) = False Then
ListBox1.Items.Add(item & " - " & Entry.getId)
End If
End If
Next
Next
Next
Example Custom Array:
(24,{"snippet","vb"})
(32,{"console","cpp","helloworld"})
and so on...
I searched for ("Snippet vb test"):
snippet vb helloWorld - 2
snippet vb tcpchatEx - 16
cs something
test
So, i'll get everything that contains one of my search phrases.
I expected following:
snippet vb tcp test
snippet vb dll test
snippet vb test metroui
So, i want to get everything that contains all my search phrases.
My entire, code-likely class
Imports Newtonsoft.Json
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Dim MainList As New List(Of EntryType)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MainList.Clear()
Dim thr As New Threading.Thread(AddressOf thr1)
thr.SetApartmentState(Threading.ApartmentState.MTA)
thr.Start()
End Sub
Delegate Sub SetTextCallback([text] As String)
Private Sub SetTitle(ByVal [text] As String) ' source <> mine
If Me.TextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetTitle)
Me.Invoke(d, New Object() {[text]})
Else
Me.Text = [text]
End If
End Sub
Sub thr1()
Dim linez As Integer = 1
Dim linex As Integer = 1
For Each line As String In System.IO.File.ReadAllLines("index.db")
linez += 1
Next
For Each line As String In System.IO.File.ReadAllLines("index.db")
Try
Application.DoEvents()
Dim a As saLoginResponse = JsonConvert.DeserializeObject(Of saLoginResponse)(line) ' source <> mine
Application.DoEvents()
MainList.Add(New EntryType(a.id, Split(a.tags, " ")))
linex += 1
SetTitle("Search (loading, " & linex & " of " & linez & ")")
Catch ex As Exception
End Try
Next
SetTitle("Search")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim searchTags() As String = TextBox1.Text.Split(" ")
Dim query = MainList.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
ListBox1.Items.Add(et.Id)
Next
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) ' test
MsgBox(Mid(ListBox1.SelectedItem.ToString, 1, 6)) ' test
End Sub 'test, removeonrelease
End Class
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As String
Public Sub New(ByVal _id As Integer, ByVal _tags() As String)
Me.Id = Id
Me.Tags = Tags
End Sub
Public Function GetTags() As String
'to tell the Listbox what to display
Return Tags
End Function
Public Function GetId() As Integer
'to tell the Listbox what to display
Return Id
End Function
End Class
I also edited your EntryType class; I added a constructor, removed toString and added GetTags and GetID.
Example "DB" im working with ("db" as "index.db" in exec dir):
{"tags":"vb.net lol test qwikscopeZ","id":123456}
{"tags":"vb.net lol test","id":12345}
{"tags":"vb.net lol","id":1234}
{"tags":"vb.net","id":123}
{"tags":"cpp","id":1}
{"tags":"cpp graphical","id":2}
{"tags":"cpp graphical fractals","id":3}
{"tags":"cpp graphical fractals m4th","id":500123}
Error:
Debugger:Exception Intercepted: _Lambda$__1, Form2.vb line 44
An exception was intercepted and the call stack unwound to the point before the call from user code where the exception occurred. "Unwind the call stack on unhandled exceptions" is selected in the debugger options.
Time: 13.11.2014 03:46:10
Thread:<No Name>[5856]

Here is a Lambda query. The Where filters on a predicate, since Tags is an Array you can use the Any function to perform a search based on another Array-SearchTags. You can store each class object in the Listbox since it stores Objects, you just need to tell it what to display(see below).
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As As String
Public Overrides Function ToString() As String
'to tell the Listbox what to display
Return String.Format("{0} - {1}", Me.Id, String.Join(Me.Tags, " "))
End Function
End Class
Dim searchTags = textbox1.Text.Split(" "c)
Dim query = mainlist.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
Listbox1.Items.Add(et)
Next

Related

Get a value by index from combobox class

i'm approaching to vbnet from vb6 and i'm triyng to get value from combobox using a class which contains the values i stored in.
here is the class
Private m_ItemText As String
Private m_ItemIndex As Int32
Public Sub New(ByVal strItemText As String, ByVal intItemIndex As Int32)
m_ItemText = strItemText
m_ItemIndex = intItemIndex
End Sub
Public ReadOnly Property ItemIndex() As Int32
Get
Return m_ItemIndex
End Get
End Property
Public ReadOnly Property ItemText() As String
Get
Return m_ItemText
End Get
End Property
I use this method charge the combobox
ComboBox2.Items.Add(New clsComboBoxItem("sometext", 1))
ComboBox2.Items.Add(New clsComboBoxItem("sometext 2", 2))
ComboBox2.Items.Add(New clsComboBoxItem("sometext", 3))
and this on combobox.selectedindexchanged
If ComboBox2.SelectedItem.GetType.ToString = itmCombo.GetType.ToString Then
itmCombo = CType(ComboBox2.SelectedItem, clsComboBoxItem)
MessageBox.Show("Item Text=" & itmCombo.ItemText & " and ItemIndex=" & CStr(itmCombo.ItemIndex))
End If
Can anyone tell help me to understand how get an element by his index stored in the class? Eg writing '2' into a text box, the combo box sould be show "sometext2".
Suppose i want to expand the class adding some values, like m_ItemText2,m_ItemText3 etc, i would learn a method to get all of theese values.
I hope I was clear
Thanks in advance
If you have a DataSource set to a DataTable for your ComboBox, just set the DisplayMember and ValueMember. My test ComboBox is set to DropDownList.
Private Sub FillComboBox()
Dim dt As New DataTable
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand("Select FlavorID,FlavorName From Flavors", con)
con.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
ComboBox1.DisplayMember = "FlavorName"
ComboBox1.ValueMember = "FlavorID"
ComboBox1.DataSource = dt
End Sub
To display the the values
To display the Text cast to DataRowView (that is the object that is in the Item), provide the field you want and call ToString.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
MessageBox.Show(ComboBox1.SelectedValue.ToString)
MessageBox.Show(DirectCast(ComboBox1.SelectedItem, DataRowView)("FlavorName").ToString)
End Sub
If you are adding items one by one, you can still set the DisplayMember and ValueMember.
'https://stackoverflow.com/questions/38206678/set-displaymember-and-valuemember-on-combobox-without-datasource
Private Sub SomeFormsLoadEvent()
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Ultra-fast", 600))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Fast", 300))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Medium", 150))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Slow", 75))
ComboBox1.DisplayMember = "Key"
ComboBox1.ValueMember = "Value"
ComboBox1.DataSource = ComboBox1.Items
End Sub
I found it a bit more complicated to display the text. I had to cast the item to its underlying type (KeyValuePair) then ask for the Key value.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
MessageBox.Show(ComboBox1.SelectedValue.ToString)
MessageBox.Show(DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, Integer)).Key)
End Sub
As I understand it you want to store values in a class and display and access them through the combobox. How about this approach:
The class for the values:
Public Class clsValues
Private lstItemTexts As New List(Of String)
Public ReadOnly Property AllValues As List(Of String)
Get
Return lstItemTexts
End Get
End Property
'To initialize class with empty list, items can be added with AddItems
Public Sub New()
End Sub
'To initialize class with items, items can still be added with AddItems
Public Sub New(lstItemTexts As List(Of String))
Me.lstItemTexts = lstItemTexts
End Sub
Public Sub AddItem(item As String)
Me.lstItemTexts.Add(item)
End Sub
Public Function GetItemByIndex(index As Integer) As String
Return lstItemTexts(index)
End Function
Public Function GetIndexByItem(item As String) As Integer
Return lstItemTexts.IndexOf(item)
End Function
End Class
You can declare it and fill values like this:
Private Values As New clsValues()
Values.AddItem("Some Text 1")
Values.AddItem("Some Text 2")
or
Private Values As New clsValues(New List(Of String)({"Some Text 1", "Some Text 2"}))
to get a value from combobox
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
MessageBox.Show(Values.GetItemByIndex(ComboBox2.SelectedIndex))
End Sub
What #Mary stated is true the ComboBox has values that are useful SEE CODE BELOW
Change gvTxType to be a TextBox to see results when you click on the tvTxType
Private Sub cbTxType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbTxType.SelectedIndexChanged
If cbTxType.SelectedIndex > -1 Then
'Dim sindex As Integer
'sindex = cbTxType.SelectedIndex
'Dim sitem As String
sitem = CType(cbTxType.SelectedItem, String)
'MsgBox("You Selected " & sitem)
'Index is ZERO based
gvTxType = sitem
End If
End Sub

Removing items in a collection based on listbox string

Having issues when clicking the remove button. If more of my code is needed, let me know. I get this error on the line AddressList.Remove(selectedName):
System.ArgumentException: 'Argument 'Key' is not a valid value.
I've tried many variations but can't figure out why this doesn't work. I think it has something to do with how the strings are concatenated in the listbox. I need to be able to remove entries from the collection and the listbox. Any help would be greatly appreciated.
Module EmailCollection
Public AddressList As New Collection
Public Sub AddRecord(ByVal a As cAddress)
Try
AddressList.Add(a)
Catch ex As Exception
MessageBox.Show("Error: inputs must be characters valid in string format")
End Try
End Sub
End Module
public class form1
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim frmAdd As New AddNewName
frmAdd.ShowDialog()
UpdateListBox()
End Sub
Private Sub UpdateListBox()
lstAddress.Items.Clear()
Dim a As cAddress
For Each a In AddressList
lstAddress.Items.Add(String.Concat(a.strName, a.strEmail, a.strPhone, a.strComment))
Next
If lstAddress.Items.Count > 0 Then
lstAddress.SelectedIndex = 0
End If
End Sub
Private Sub btnRemove_Click(sender As Object, e As EventArgs) Handles btnRemove.Click
Dim selectedName As String
Try
' Get the selected value.
selectedName = lstAddress.SelectedItem.ToString()
' Remove the selected name from the list box and the collection.
If MessageBox.Show("Are you sure?",
"Confirm Deletion",
MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
lstAddress.Items.Remove(selectedName)
AddressList.Remove(selectedName)
End If
Catch ex As NullReferenceException
MessageBox.Show("Select an item to remove.", "Selection Needed")
End Try
End Sub
end class
In your Module I changed AddressList from the old VB6 Collection type to the .net List(Of T). The T stands for Type.
Module EmailCollection
Public AddressList As New List(Of cAddress)
Public Sub AddRecord(ByVal a As cAddress)
AddressList.Add(a)
End Sub
End Module
I guessed that your cAddress class looks something like this. I added a custom .ToString method so the list box will display the data you wish but the item, itself, will be a cAddress object.
Public Class cAddress
Public Property strName As String
Public Property strEmail As String
Public Property strPhone As String
Public Property strComment As String
Public Overrides Function ToString() As String
Return $"{strName}, {strEmail}, {strPhone}, {strComment}"
End Function
End Class
In the Form...
Instead of adding a string to the list box I added the cAddress object. The list box calls .ToString on the object to get the display value.
Private Sub UpdateListBox()
ListBox1.Items.Clear()
For Each a As cAddress In AddressList
ListBox1.Items.Add(a)
Next
If ListBox1.Items.Count > 0 Then
ListBox1.SelectedIndex = 0
End If
End Sub
In the remove button I cast the selected item to its underlying type, cAddress. This is the item removed from the AddressList. Then simply remove the selected item from the list box.
Private Sub btnRemove_Click(sender As Object, e As EventArgs) Handles btnRemove.Click
If MessageBox.Show("Are you sure?",
"Confirm Deletion",
MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
AddressList.Remove(DirectCast(ListBox1.SelectedItem, cAddress))
ListBox1.Items.Remove(ListBox1.SelectedItem)
End If
End Sub
I changed the name of the list box to ListBox1 to match my test project.
Here is something to try, use a BindingSource for setting up the ListBox. In the class override ToString to what is to be shown in the ListBox rather than what you are doing now without a DataSource.
My version of your class has name and property name changes.
Public Class Address
Public Property Name() As String
Public Property Email() As String
Public Property Phone() As String
Public Property Comment() As String
Public Overrides Function ToString() As String
Return $"{Name} {Email} {Phone} {Comment}"
End Function
End Class
Mocked data is used to populate the ListBox
Public Class Form1
Private ReadOnly _bsAddresses As New BindingSource
Private Sub UpdateListBox()
Dim AddressList = New List(Of Address) From
{
New Address() With {
.Name = "John",
.Email = "john#gmail.com",
.Phone = "555-444-3456",
.Comment = "AAA"},
New Address() With {
.Name = "Mary",
.Email = "mary#gmail.com",
.Phone = "888-333-2222",
.Comment = "BBB"},
New Address() With {
.Name = "Bob",
.Email = "bob#gmail.com",
.Phone = "111-555-9999",
.Comment = "CCC"}
}
_bsAddresses.DataSource = AddressList
lstAddress.DataSource = _bsAddresses
lstAddress.SelectedIndex = 0
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) _
Handles Me.Shown
UpdateListBox()
End Sub
Private Sub RemoveButton_Click(sender As Object, e As EventArgs) _
Handles RemoveButton.Click
If lstAddress.Items.Count > 0 AndAlso lstAddress.SelectedItem IsNot Nothing Then
Dim address = CType(_bsAddresses.Current, Address)
If My.Dialogs.Question($"Remove {address.Name}") Then
_bsAddresses.RemoveCurrent()
RemoveButton.Enabled = _bsAddresses.Count > 0
End If
End If
End Sub
End Class
Code module for asking a question
Namespace My
<ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)>
Partial Friend Class _Dialogs
Public Function Question(text As String) As Boolean
Return (MessageBox.Show(
text,
My.Application.Info.Title,
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) = MsgBoxResult.Yes)
End Function
End Class
<HideModuleName()>
Friend Module WinFormsDialogs
Private instance As New ThreadSafeObjectProvider(Of _Dialogs)
ReadOnly Property Dialogs() As _Dialogs
Get
Return instance.GetInstance()
End Get
End Property
End Module
End Namespace
Karen's post seems quite comprehensive. My response is an attempt to focus on your direct question.
I don't see all of the type definitions shown in your code, but in answer to your question, which I believe is "Why am I getting System.ArgumentException: 'Argument 'Key' is not a valid value":
In the offending line of code:
AddressList.Remove(selectedName)
AddressList is a collection. To use .Remove, you must pass in an object of the AddressList collection to remove it. You are passing a simple string, and that is not an AddressList object. You need to create an object based on your string selectedName to pass into .Remove and that line should work. The rest of what you are doing seems more complex.

How to use IO.File.WriteAllLines(FileName, OutputArray) in VB

When using this code in VB I get the error:
System.InvalidCastException: 'Unable to cast object of type 'System.Collections.ArrayList' to type 'System.Collections.Generic.IEnumerable`1[System.String]'.'
Can someone please give me the correct usage?
Full code:
Public Class Form1
Dim OutputArray As New ArrayList
Dim i = 0
Dim Registrationdata
Dim FileName As String = Application.StartupPath & "\Output.txt"
Private Sub IssueTicket_Click(sender As Object, e As EventArgs) Handles IssueTicket.Click
Dim Speed As Integer
If Integer.TryParse(Speedbox.Text(), Speed) Then
If Speed <= 20 Or Speed > 300 Then
MessageBox.Show("Please enter a valid speed between 20-200")
ElseIf Registrationbox.Text() = Nothing Or Not Registrationbox.Text() Like "???? ???" Then
MessageBox.Show("Please enter a vaild registration to continue e.g '1234 123'.")
ElseIf Not IDBox.Text().StartsWith("9") Or Not IDBox.TextLength = 6 Or Not IsNumeric(IDBox.Text()) Then
MessageBox.Show("Please enter a valid OfficerID starting with '9' and is 6 numbers long.")
Else
OutputArray.Add(Speed)
OutputArray.Add(Registrationbox.Text())
OutputArray.Add(IDBox.Text())
MessageBox.Show("Ticket saved")
i += 1
End If
End If
End Sub
Private Sub SaveToFile_Click(sender As Object, e As EventArgs) Handles SaveToFile.Click
Registrationbox.Text() = Registrationdata
IO.File.WriteAllLines(FileName, OutputArray)
End Sub
End Class
To solve your problem quickly you could change your code to:
Dim OutputArray As New List(Of String)
...
OutputArray.Add(Speed.ToString())
OutputArray.Add(Registrationbox.Text())
OutputArray.Add(IDBox.Text())
Problem with your code is that ArrayList doesn't implement an IEnumerable interface, while List does and so File.WriteAllText works; but List(Of String) wants all the items to be of type string, so you have to convert your int to string before pushing it into the list.

VB.NET Search ListBox for string and return specific data

I have a populated listbox. Each item has a string of data with id's and values. How would i search for the id and receive the vale?
If i search for 'itemColor' i would like it to return each boot color in a new msgbox.
itemName="boots" itemCost="$39" itemColor="red"
itemName="boots" itemCost="$39" itemColor="green"
itemName="boots" itemCost="$39" itemColor="blue"
itemName="boots" itemCost="$39" itemColor="yellow"
I understand there are different and easier ways to do this but i need to do it this way.
Thanks!
Here's one way to do it involving parsing the text as XML:
' Here's Some Sample Text
Dim listboxText As String = "itemName=""boots"" itemCost=""$39"" itemColor=""red"""
' Load XML and Convert to an Object
Dim xmlDocument As New System.Xml.XmlDocument
xmlDocument.LoadXml("<item " & listboxText & "></item>")
Dim item = New With {.ItemName = xmlDocument.DocumentElement.Attributes("itemName").Value,
.ItemCost = xmlDocument.DocumentElement.Attributes("itemCost").Value,
.ItemColor = xmlDocument.DocumentElement.Attributes("itemColor").Value}
' Write It Out as a Test
Console.WriteLine(item.ItemName & " " & item.ItemCost & item.ItemColor)
Console.Read()
Create a class (or structure), the appropriate properties, a default constructor, a parametized constructor and an Override of .ToString.
Public Class Item
Public Property Name As String
Public Property Cost As String
Public Property Color As String
Public Sub New()
End Sub
Public Sub New(sName As String, sCost As String, sColor As String)
Name = sName
Cost = sCost
Color = sColor
End Sub
Public Overrides Function ToString() As String
Return $"{Name} - {Cost} - {Color}"
End Function
End Class
Item objects are added to the list box calling the parameterized constructor. The list box calls .ToString on the objects to determine what to display.
Private Sub FillList()
ListBox3.Items.Add(New Item("boots", "$39", "red"))
ListBox3.Items.Add(New Item("boots", "$39", "green"))
ListBox3.Items.Add(New Item("boots", "$39", "blue"))
ListBox3.Items.Add(New Item("boots", "$39", "yellow"))
End Sub
Since we added Item objects to the list box, we can cast each list item back to the Item type and access its properties.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sb As New StringBuilder
For Each i In ListBox3.Items
sb.AppendLine(DirectCast(i, Item).Color)
Next
MessageBox.Show(sb.ToString)
End Sub

Own class can't convert string to integer

https://imgur.com/a/gaXh4
Ok so I have a problem a really weird problem. So I created a new class which is a new type of TextBox. It keeps track of the objects created from it with the help of a list but. This all works, with for each I can get all objects of the class but when I want to convert the string from the TextBox into a integer I can't do it because it thinks its not convertable eventhought the string only consists out of number symbols
Code for Button
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'TextBox1.Text = CInt(SumTextBox1.Text) + CInt(SumTextBox2.Text)
For Each item As SumTextBox In SumTextBox.sumList
Dim textItem As SumTextBox = item
TextBox1.Text = CInt(TextBox1.Text) + CInt(textItem.Text)
Next
End Sub
Public Class SumTextBox
Inherits TextBox
Public Shared sumList As New List(Of SumTextBox)
Sub New()
Size = New Size(90, 10)
sumList.Add(Me)
End Sub
End Class
Try using Convert.toInt32(TextBox1.Text) and the same for textitem.text