Issue with item order in List and CheckedListBox - vb.net

I have 2 CheckedListBox that contains 3 strings each:
CheckedListBox1: "Apricot", "Banana", "Cherry"
CheckedListBox2: "Apple", "Blueberry", "Clementine"
I would like that everytime I click on my Button1, it checks if it contains the item, and if not it adds it to myList1 for CheckedListBox1, and myList2 for CheckedListBox2, but in the same order. I mean:
I check Apricot and Cherry, so myList1 is: "Apricot", "Cherry"
I uncheck them and check only Banana, so the list is: "Apricot", "Cherry", "Banana"
So I want the Apricot always being first, Banana second and Cherry third.
Same for myList2, obviously.
My actual code is:
Dim myList1 As New List(Of String)
Dim myList2 As New List(Of String)
Dim myFullList As New List(Of String)
Private Sub Submit() Handles Button1.Click
For Each item In CheckedListBox1.CheckedItems
If Not myList1.Contains(item) Then
myList1.Add(item)
End If
Next
For Each item In CheckedListBox2.CheckedItems
If Not myList2.Contains(item) Then
myList2.Add(item)
End If
Next
myFullList.Add(String.Join(", ", myList1)
myFullList.Add(String.Join(", ", myList2)
End Sub
Thanks in advance, guys ! :)

You might consider doing things a bit differently. Define a custom type and bind a list of that type to the CheckedListBox. When an item is checked, set a flag in that item. You can then just get the items from that list that have that flag set.
Public Class CheckListItem
Public Property Text As String
Public Property Checked As Boolean
Public Overrides Function ToString() As String
Return Text
End Function
End Class
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim items = {New CheckListItem With {.Text = "Apricot"},
New CheckListItem With {.Text = "Banana"},
New CheckListItem With {.Text = "Cherry"}}
CheckedListBox1.DataSource = items
End Sub
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
If e.NewValue = CheckState.Checked Then
DirectCast(CheckedListBox1.Items(e.Index), CheckListItem).Checked = True
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim checkedItems = CheckedListBox1.Items.Cast(Of CheckListItem)().Where(Function(cli) cli.Checked)
MessageBox.Show(String.Join(", ", checkedItems))
End Sub

Related

Passing data through form with showdialog but without closing event

I have a first form (form_notice_hashtag) called like this:
Public Sub afficher_hashtag(hashtag As String, plateforme_hashtag As String)
Dim form_notice_hashtag_1 As New form_notice_hashtag
form_notice_hashtag_1.StartPosition = FormStartPosition.CenterScreen
form_notice_hashtag_1.Show()
End Sub
In form_notice_hashtag_1, i have a button calling a 2nd form (form_recherche_thesaurus) like this:
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
form_recherche_thesaurus_1.ShowDialog(Me)
End Sub
In form_recherche_thesaurus, i have a datagridview listing some words. The user can select one word, then by clicking a button in form_recherche_thesaurus, the word which will be added to a textbox in form_notice_hashtag
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Select Case Owner.Name.ToString
Case "form_notice_hashtag"
list_terms_array = Split(Remove_Duplicates_From_Strings_With_SemiColon(form_notice_hashtag.hashtag_descripteurs_txtbox.Text & ";" & selected_term), ";")
form_notice_hashtag.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Select
End Sub
I used a select because this mechanism would be used in the same way with other forms than form_notice_hashtag.
Problem: the textbox in form_notice_hashtag is not filled with the selected keywords. I guess it's because of the way form_notice_hashtag is called.
I can't use the solution as explained here Send values from one form to another form because i understood (maybe badly) that this solution works only if the 2nd form (form_recherche_thesaurus in my case) is closed (i.e closing was the trigger) which i don't want.
How can I proceed?
Thanks to jmcilhinney and this page of his blog, here is the solution that allows to transfer several data from a called form (form_recherche_thesaurus) to a calling form (form_notice_hashtag) without closing the called form .
Public Class form_notice_hashtag
Private WithEvents form_recherche_thesaurus_1 As form_recherche_thesaurus
Private selected_thesaurus_term As String
Private Sub form_recherche_thesaurus_1_TextBoxTextChanged(sender As Object, e As EventArgs) Handles form_recherche_thesaurus_1.TextBoxTextChanged
Dim list_terms_array As String() = Split(Remove_Duplicates_From_Strings_With_SemiColon(Me.hashtag_descripteurs_txtbox.Text & ";" & form_recherche_thesaurus_1.selected_term), ";")
Me.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Sub
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
If Me.form_recherche_thesaurus_1 Is Nothing OrElse Me.form_recherche_thesaurus_1.IsDisposed Then
Me.form_recherche_thesaurus_1 = New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
Me.form_recherche_thesaurus_1.Show()
End If
Me.form_recherche_thesaurus_1.Activate()
End Sub
End Class
Public Class form_recherche_thesaurus
Public Event TextBoxTextChanged As EventHandler
Private term_thesaurus As String
Public Property selected_term() As String
Get
Return term_thesaurus
End Get
Set(ByVal value As String)
term_thesaurus = value
End Set
End Property
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Me.selected_term = Me.thesaurus_search_results_datagrid.Item(0, Me.thesaurus_search_results_datagrid.CurrentRow.Index).Value
Me.DialogResult = DialogResult.OK
RaiseEvent TextBoxTextChanged(Me, EventArgs.Empty)
End Sub

0 added to listbox2 display when item selected in Listbox1

1.When I select an item from my listbox1 it shows information about the item in listbox2. However, when I click an item in listbox1 it shows me the info and adds a 0 to the end of it in listbox2. How do I get rid of the 0 or what am I doing that is causing this? I think it is displaying the index number perhaps. Here is my code-
If ListBox1.SelectedIndex = 2 Then ListBox2.Items.Add("60137" & ListBox2.Items.Add("60138"))
2.Also, How would I clear List2 when I choose a different item in list1 so that they dont both populate list2 at the same time?
*Ignoring the fact that this is a horrible design...
Change:
If ListBox1.SelectedIndex = 2 Then ListBox2.Items.Add("60137" & ListBox2.Items.Add("60138"))
To:
If ListBox1.SelectedIndex = 2 Then
ListBox2.Items.Clear
ListBox2.Items.Add("60137")
End If
Here is an alternative approach:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim petA As New Pet
petA.Name = "Puss in Boots"
petA.Species = "Cat"
ListBox1.Items.Add(petA)
Dim petB As New Pet
petB.Name = "Nemo"
petB.Species = "Fish"
ListBox1.Items.Add(petB)
Dim petC As New Pet
petC.Name = "Rango"
petC.Species = "Lizard"
ListBox1.Items.Add(petC)
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
If ListBox1.SelectedIndex <> -1 Then
Dim P As Pet = DirectCast(ListBox1.SelectedItem, Pet)
Label1.Text = P.Species
End If
End Sub
End Class
Public Class Pet
Public Name As String
Public Species As String
Public Overrides Function ToString() As String
Return Name
End Function
End Class

Adding Selected Item in a Listbox to a Label in Visual Basic

In the program I'm writing I'm stuck on one of the last steps which is to display an employee's name and salary selected from a listbox in labels (one for the name and one for the salary), but I cannot figure out how to do this. The employee's names and salaries are read in from a file and are placed in the corresponding listboxes on 3 different forms (two that only list names, and one that only lists salaries). On the last form, the user is supposed to select the name of one of the employees and that person's name is supposed to appear in one label (lblName) and their salary is supposed to appear in another label (lblSalary). The names are listed in the selectable listbox, but when I click on one of them nothing happens.
Here is the code I have so far on the main form:
Option Strict On
Imports System.IO
Public Class Main
Private Sub open_Click(sender As Object, e As EventArgs) Handles open.Click
Dim open As New OpenFileDialog
open.Filter = "text files |*.txt|All Files|*.*"
open.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
If open.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim selectedFileName As String = System.IO.Path.GetFileName(open.FileName)
showNames.Enabled = True
showSalaries.Enabled = True
showEmployee.Enabled = True
End If
Dim container As New List(Of Project9)
Using reader As New StreamReader(open.OpenFile)
While Not reader.EndOfStream
Dim employee As New Project9
employee.Name = reader.ReadLine()
employee.Salary = CDbl(reader.ReadLine())
container.Add(employee)
End While
End Using
For Each item As Project9 In container
Names.lstNames.Items.Add(item.Name)
frmTotal.lstShow.Items.Add(item.Name)
Salaries.lstSalaries.Items.Add(item.Salary)
Next
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Me.Close()
Names.Close()
Salaries.Close()
frmTotal.Close()
End Sub
Private Sub showNames_Click(sender As Object, e As EventArgs) Handles showNames.Click
Names.Show()
End Sub
Private Sub showSalaries_Click(sender As Object, e As EventArgs) Handles showSalaries.Click
Salaries.Show()
End Sub
Private Sub showEmployee_Click(sender As Object, e As EventArgs) Handles showEmployee.Click
frmTotal.Show()
End Sub
End Class
Public Class Project9
Dim strName As String
Dim dblSalary As Double
Public Property Name As String
Get
Return strName
End Get
Set(value As String)
strName = value
End Set
End Property
Public Property Salary As Double
Get
Return dblSalary
End Get
Set(value As Double)
If dblSalary < 0 Then
dblSalary = 10
End If
dblSalary = value
End Set
End Property
Public Function computeSalary(intMonths As Integer) As Double
Dim dblTotal As Double = dblSalary * intMonths
Return dblTotal
End Function
End Class
And here's the code from the 4th form which is the one displaying the selected item in labels:
Public Class frmTotal
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
lblName.Text = lstShow.SelectedItem(Name)
Dim intMonths As Integer
intMonths = InputBox("How many months would you like to calculate this employee's salary for?")
End Sub
End Class
Also, how would I be able to make a button visible only after an item has been selected?
Any help would be greatly appreciated.
If you leverage the Datasource property of the listbox you can actually fill the listbox with Project9 items and use the DisplayMember property to choose which property you display in the listbox. This has several advantages. Whenever a listbox item is selected it can be cast as an object of type Project9 and you can display whichever properties you want to the labels. Also the selection is tied together across the listboxes so that a selection in one is the same selection in the others. Here's an example of how that might look:
Dim employees As New List(Of Project9)(
{
New Project9 With {.Name = "A", .Salary = 1000},
New Project9 With {.Name = "B", .Salary = 1200},
New Project9 With {.Name = "C", .Salary = 1100}
})
ListBox1.DataSource = employees
ListBox1.DisplayMember = "Name"
ListBox2.DataSource = employees
ListBox2.DisplayMember = "Salary"
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim selectedemployee = DirectCast(ListBox1.SelectedItem, Project9)
Label1.Text = selectedemployee.Name
Label2.Text = selectedemployee.Salary.ToString
End Sub

Refreshing Listbox in VB.Net

I was wondering if there is any way to refresh the cont numbers in a listbox
i am adding data with the code
ListBox1.Items.Add
I have set up as button to remove selected data with the code:
For i As Integer = ListBox1.SelectedIndices.Count - 1 To 0 Step -1
ListBox1.Items.RemoveAt(ListBox1.SelectedIndices.Item(i))
Next
say my list box is like this
Zach
Barry
John
Nick
Brodie
if i deleted say barry how can i make the numbers change so john would be 2. etc
The BindingList can be helpful here since it can listen for changes in the list.
For example, create a Person class and override the ToString function to show the rank and the name.
Public Class Person
Property Name As String
Property Rank As Integer
Public Overrides Function ToString() As String
Return Rank & ". " & Name
End Function
End Class
In your form, declare the list and add the event handler:
Private people As New BindingList(Of Person)
Public Sub New()
InitializeComponent()
AddHandler people.ListChanged, AddressOf people_ListChanged
people.Add(New Person() With {.Name = "Zach"})
people.Add(New Person() With {.Name = "Barry"})
people.Add(New Person() With {.Name = "John"})
people.Add(New Person() With {.Name = "Nick"})
people.Add(New Person() With {.Name = "Brodie"})
ListBox1.DataSource = people
End Sub
Private Sub people_ListChanged(sender As Object, e As ListChangedEventArgs)
For i As Integer = 0 To people.Count - 1
people(i).Rank = i + 1
Next
End Sub
The ListChanged event just updates the ranking of each member as they as slotted in the list, which will automatically update the ListBox since the DataSource is coming from the people list.
A simple delete button to test the list, and the rankings are automatically updated in the people list, which automatically updates the ListBox:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ListBox1.SelectedIndex > -1 Then
people.Remove(ListBox1.SelectedItem)
End If
End Sub
If you have some idea of GDI+ drawing, a more interesting approach is to set your ListBox's DrawMode to OwnerDrawFixed mode and listen to ListBox's DrawItem event, something like this:
C#
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
e.Graphics.DrawString((e.Index + 1).ToString() + ". " + listBox1.Items[e.Index].ToString(), listBox1.Font, Brushes.Black, e.Bounds);
}
VB.NET
Private Sub listBox1_DrawItem(sender As Object, e As DrawItemEventArgs)
e.DrawBackground()
e.Graphics.DrawString((e.Index + 1).ToString() & ". " & listBox1.Items(e.Index).ToString(), listBox1.Font, Brushes.Black, e.Bounds)
End Sub
Adding or removing any items to the ListBox will automatically renumber all the items.
You can use a List of string combined with the ListBox.
Dim NamesList1 As New List(Of String)
Private Sub Form_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
NamesList1.AddRange({"Zach", "Barry", "John", "Nick", "Brodie"})
FillListBoxItems()
End Sub
Private Sub FillListBoxItems()
ListBox1.Items.Clear()
For i As Integer = 0 To NamesList1.Count - 1
ListBox1.Items.Add(i + 1 & ". " & NamesList1.Item(i))
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
For i As Integer = ListBox1.SelectedIndices.Count - 1 To 0 Step -1
NamesList1.RemoveAt(ListBox1.SelectedIndices.Item(i))
Next
FillListBoxItems()
End Sub

vb2008 search through listbox using textbox

hi I have a form that find, or should I say filter, the items in a listbox using a textbox. I have a textbox used for searching and a listbox populated with items from database. Now, say listbox items include apple, banana, berry, cashew, lemon, mango, peanut. If I typed 'b' on the textbox, listbox only show banana and berry..if I typed 'ba' then listbox only show banana but if I typed 'be' then it shows berry and so on. I already got this working (with the code marked as commented in the txtSearch event). My problem is that how can I bring the items in the listbox back when the user strike the backspace? Because, say I have banana and berry in the listbox now, when I erased the text that I typed in the textbox it should list back all the items again so that if I want to search another item it will be filtered again. thanks in advance.
Code Update
Public Class Glossary
Private Sub Glossary_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call List()
Refreshlist()
End Sub
Private Sub List()
Dim myCmd As New MySqlCommand
Dim myReader As MySqlDataReader
Dim myAdptr As New MySqlDataAdapter
Dim myDataTable As New DataTable
Call Connect()
With Me
STRSQL = "Select word from glossary"
Try
myCmd.Connection = myConn
myCmd.CommandText = STRSQL
myReader = myCmd.ExecuteReader
If (myReader.Read()) Then
myReader.Close()
myAdptr.SelectCommand = myCmd
myAdptr.Fill(myDataTable)
lstword.DisplayMember = "word"
lstword.ValueMember = "word"
If myDataTable.Rows.Count > 0 Then
For i As Integer = 0 To myDataTable.Rows.Count - 1
lstword.Items.Add(myDataTable.Rows(i)("word"))
Next
End If
End If
'lstword.Items.Clear()
'lstword.Items.AddRange(word.Where(Function(word) word.ToString().Contains(txtSearch.Text)).ToArray())
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
myReader = Nothing
myCmd = Nothing
myConn.Close()
Call Disconnect()
End With
End Sub
Dim word As List(Of Object)
Private Sub Refreshlist()
lstword.Items.Clear()
lstword.Items.AddRange(word.Where(Function(word) word.ToString().Contains(txtSearch.Text)).ToArray())
End Sub
Private Sub txtSearch_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtSearch.TextChanged
lstword.Items.Clear()
lstword.Items.AddRange(word.Where(Function(word) word.ToString().Contains(txtSearch.Text)).ToArray())
Refreshlist()
'Call List()
'lstword.BeginUpdate()
'Try
' ' keep track of the "non-searched items" '
' Dim word As New List(Of Object)
' lstword.SelectedIndices.Clear()
' If txtSearch.Text.Length > 0 Then
' For index As Integer = 0 To lstword.Items.Count - 1
' Dim item As String = lstword.Items(index).ToString()
' If item.IndexOf(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) >= 0 Then
' lstword.SelectedIndices.Add(index)
' Else
' ' this item was not searched for; we will remove it '
' word.Add(index)
' End If
' Next
' ' go backwards to avoid problems with indices being shifted '
' For i As Integer = word.Count - 1 To 0 Step -1
' Dim indexToRemove As Integer = word(i)
' lstword.Items.RemoveAt(indexToRemove)
' Next
' End If
'Finally
' lstword.EndUpdate()
'End Try
End Sub
End Class
The first step is to store the items in off-screen memory. For instance:
Dim words As List(Of Object)
Then when you refresh the list box, only populate it with the items from that in-memory list which match the current criteria:
lstword.Items.Clear()
lstword.Items.AddRange(
words.FindAll(
Function(word) Return word.ToString().Contains(txtSearch.Text)
).ToArray()
)
Or, using LINQ:
lstword.Items.Clear()
lstword.Items.AddRange(
words.Where(
Function(word) word.ToString().Contains(txtSearch.Text)
).ToArray()
)
UPDATE
Since you seem to be having trouble getting it working, and it's hard to say what's wrong with your code without actually seeing it, here's a complete working example:
Public Class Form1
Dim words As New List(Of Object)(New String() {"apple", "banana", "berry", "cashew", "lemon", "mango", "peanut"})
Private Sub RefreshList()
lstword.Items.Clear()
lstword.Items.AddRange(
words.Where(
Function(word) word.ToString().Contains(txtSearch.Text)
).ToArray()
)
End Sub
Private Sub txtSearch_TextChanged(sender As Object, e As EventArgs) Handles txtSearch.TextChanged
RefreshList()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
RefreshList()
End Sub
End Class
UPDATE 2
I tried using your code with my recommended suggestions and it worked fine. Here's the code that worked for me. Try it and let me know if it doesn't work for you:
Public Class Glossary
Private Sub Glossary_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
List()
Refreshlist()
End Sub
Private Sub List()
word.AddRange(New String() {"apple", "banana", "berry", "cashew", "lemon", "mango", "peanut"})
End Sub
Private word As New List(Of Object)()
Private Sub Refreshlist()
lstword.Items.Clear()
lstword.Items.AddRange(word.Where(Function(word) word.ToString().Contains(txtSearch.Text)).ToArray())
End Sub
Private Sub txtSearch_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtSearch.TextChanged
Refreshlist()
End Sub
End Class
If that works, then all you need to do is change the List method to load from the database instead of being a hard-coded list.
Get your initial list off the database, pop it in a List class e.g List.
The use your search text to select all the matching items and put them in the list box. Blank search text you just put all of them in.
You might want to have a look at Foreach and List.FindAll as well.