So I have a listbox, filled with informations from a structure tab as follows :
Private Sub Modifier_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 0 To frmConnecter.TabPolyFlix.Length - 1
ListBox1.Items.Add(frmConnecter.TabPolyFlix(i).strTitre)
Next
End Sub
And I want the user to choose to delete the TabPolyFlix(ListBox1.SelectedIndex) and it has to get updated in the original Tab and thus in the Listbox
P.S I tried this but it only updates it in the listbox, not in the original tab
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim Temp As New List(Of ListViewItem)
For i As Integer = 0 To ListBox1.Items.Count - 1
If ListBox1.SelectedIndices.Contains(i) = False Then
Temp.Add(ListBox1.Items(i))
End If
Next
ListBox1.Items.Clear()
For i As Integer = 0 To Temp.Count - 1
ListBox1.Items.Add(Temp(i))
Next i
End Sub
Arrays have a fixed size. Better use a List(Of ListViewItem) for TabPolyFlix. Then assign the List directly to the DataSource of the listbox:
'Fill the listbox
ListBox1.DisplayMember = "strTitre" 'You can also set this in the property grid.
ListBox1.DataSource = frmConnecter.TabPolyFlix
You can also override the ToString method of ListViewItem in order to display anything you want in the listbox and keep ListBox1.DisplayMember empty.
Now you can directly delete the item in the list:
frmConnecter.TabPolyFlix.Remove(ListBox1.SelectedItem)
or
frmConnecter.TabPolyFlix.RemoveAt(ListBox1.SelectedIndex)
or if you want to delete several items at once
For Each i As Integer In ListBox1.SelectedIndices.Cast(Of Integer)()
frmConnecter.TabPolyFlix.Remove(ListBox1.Items(i))
Next
and re-display the list:
ListBox1.DataSource = Nothing
ListBox1.DataSource = frmConnecter.TabPolyFlix
The moral of the story is: don't use controls (the ListBox in this case) as your primary data structure. Use it only for display and user interaction. Perform the logic (the so called business logic) on display-independent data structures and objects (so called business objects) and when finished, display the result.
Related
What i need to do is take input 10 times from a text box, store it in an array and then display the array onto a list box.
I came up with this for loop but it doesn't work, all it does is display the first input and then the rest are just blank:
For i As Integer = 0 To 9
ArrNames(i) = txtUserInput.Text
txtUserInput.Clear()
Next i
and i have a different button to display the array and i used this:
lstDisplay.DataSource = ArrNames
can anyone help me? iv'e looked everywhere and nothing worked for me
Edit 1:
So i changed it a lot and came up with this:
Dim I As Integer
If sender Is btnEnter Then
I = I + 1
End If
ArrNames(I) = txtUserInput.Text
txtUserInput.Clear()
is what it does is if the button is pressed it increases I by one which makes it so the input goes to the right index right?
but now that i make this it stopped displaying anything at all so this:
Private Sub btnShow_Click(sender As Object, e As EventArgs) Handles btnShow.Click
lstDisplay.DataSource = ArrNames
stopped working
Hopefully that I variable is declared at class level in the same place as the array.
To force the ListBox to refresh you have to set the .DataSource to Nothing and then back to your array again:
Public Class Form1
Private I As Integer
Private ArrNames(9) As String
Private Sub btnAddName_Click(sender As Object, e As EventArgs) Handles btnAddName.Click
If I < ArrNames.Length Then
If txtUserInput.Text.Trim.Length > 0 Then
ArrNames(I) = txtUserInput.Text
I = I + 1
lstDisplay.DataSource = Nothing
lstDisplay.DataSource = ArrNames
txtUserInput.Clear()
txtUserInput.Focus()
Else
MessageBox.Show("Enter a name first!")
End If
Else
MessageBox.Show("The array is full!")
End If
End Sub
End Class
I would first recommend you to use typed Lists instead of using the old fashioned array (discussions incoming.. but..).
You can also make use of the nice feature of Enumerable.Range().
I don't have my editor right now but it should look like:
Dim list = new List(Of string)
For i In Enumerable.Range(1, 10)
list.Add(txtUserInput.Text)
Next
txtUserInput.Clear()
lstDisplay.DataSource = list
If you plan to modify your list afterwards and e.g. keep it on class scope, then you should use a BindingList(Of String) which supports notifying about changes.
Edit 1:
You are calling txtUserInput.Clear() inside the loop after the first time your input has been received from the textbox. That means in each following iteration the textbox is cleared.
I have a CheckedListBox of 10 names A to J (it's a string but here I'm just using abc), and I want to make it so that every time a user check something, the text will be shown in the listbox simultaneously. I have tried this:
For i = 0 To chklistbxDrugAvailableList.Items.Count - 1
Dim drugs As String = CType(chklistbxDrugAvailableList.Items(i), String)
If chklistbxDrugAvailableList.GetItemChecked(i) Then
listbxYourOrder.Items.Add(drugs)
End If
'drugs = nothing
Next
But when I check A,B,C the text in the Listbox got repeated like so:
A
A
B
A
B
C
I don't know why this is happening. I didn't declare drugs as an array. Even when I used the drugs = nothing, it still give repeated values.
What should I do? Sorry if this is a noob question.
Here is how I would do the whole thing:
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
'Clear the current ListBox contents.
ListBox1.Items.Clear()
'Get the indexes of the currently checked items.
Dim checkedIndices = CheckedListBox1.CheckedIndices.Cast(Of Integer)()
'Add the current index to the list if the item is being checked, otherwise remove it.
checkedIndices = If(e.NewValue = CheckState.Checked,
checkedIndices.Append(e.Index),
checkedIndices.Except({e.Index}))
'Get the checked items in order and add them to the ListBox.
ListBox1.Items.AddRange(checkedIndices.OrderBy(Function(n) n).
Select(Function(i) CheckedListBox1.Items(i)).
ToArray())
End Sub
or like this:
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
'Get the indexes of the currently checked items.
Dim checkedIndices = CheckedListBox1.CheckedIndices.Cast(Of Integer)()
'Add the current index to the list if the item is being checked, otherwise remove it.
checkedIndices = If(e.NewValue = CheckState.Checked,
checkedIndices.Append(e.Index),
checkedIndices.Except({e.Index}))
'Get the checked items in order and add them to the ListBox.
ListBox1.DataSource = checkedIndices.OrderBy(Function(n) n).
Select(Function(i) CheckedListBox1.Items(i)).
ToArray()
End Sub
The difference is that, because the second option uses data-binding, the first item in the ListBox will be selected by default.
The reason that it needs to be a bit verbose is that the ItemCheck event is raised before the item is checked or unchecked. For that reason, we need to get the currently checked items first and then either add or remove the current item, depending on whether the current item is being checked or unchecked.
EDIT:
Here's an option that doesn't require clearing the ListBox:
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
Dim item = CheckedListBox1.Items(e.Index)
If e.NewValue = CheckState.Checked Then
ListBox1.Items.Add(item)
Else
ListBox1.Items.Remove(item)
End If
End Sub
The issue with that is that the items will appear in the ListBox in the order you checked them, rather than the order they appear in the CheckedListBox. The other options keep the items in the same order in both lists.
If I understand your question I would this:
lstbxYourOrder.Items.Clear()
For Each l As String In chklistbxDrugAvailableList.CheckedItems
listbxYourOrder.Items.Add(l)
Next
Sorry, I have three linked lists in a form1 and three in a form2 (with the same name) and i want to pass specific selected linked items on the linked lists of the form1 to the linked lists of the form 2.
For Each lists In {frm2.lst1, frm2.lst2, frm2.lst3}
lists.Items.Add(DirectCast(Controls(lists.Name), ListBox).SelectedItem)
'this is supposed to add the linked items on the form1 (DirectCast(Controls(lists.Name), ListBox).SelectedItem) to the linked lists on form2
DirectCast(Controls(lists.Name), ListBox).Items.RemoveAt(DirectCast(Controls(lists.Name), ListBox).SelectedIndex)
'this is supposed to removes the selected linked items on the form1
Next
If i do this, it works:
Dim a = lst1.selectedindex
For Each lists In {frm2.lst1, frm2.lst2, frm2.lst3}
lists.Items.Add(DirectCast(Controls(lists.Name), ListBox).SelectedItem)
Next
For Each lists In {frm2.lst1, frm2.lst2, frm2.lst3}
DirectCast(Controls(lists.Name), ListBox).Items.RemoveAt(a)
Next
But I want to know how make it in the same for each
There's a better way to do this, IMHO:
Make a new form, drop 4 listboxes on it (named listbox1, 2, 3, and 4) and paste this code in:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim d As New DataTable
d.Columns.Add("ShowText")
d.Columns.Add("WhichList", GetType(Integer))
d.Rows.Add("I started in LB1", 1)
d.Rows.Add("I started in LB1 too", 1)
d.Rows.Add("I started in LB1 also", 1)
d.Rows.Add("I started in LB2", 2)
d.Rows.Add("I started in LB2 too", 2)
d.Rows.Add("I started in LB2 also", 2)
d.Rows.Add("I started in LB3", 3)
d.Rows.Add("I started in LB3 too", 3)
d.Rows.Add("I started in LB3 also", 3)
ListBox1.DataSource = New DataView(d) With {.RowFilter = "[WhichList] = 1"}
ListBox1.DisplayMember = "ShowText"
ListBox2.DataSource = New DataView(d) With {.RowFilter = "[WhichList] = 2"}
ListBox2.DisplayMember = "ShowText"
ListBox3.DataSource = New DataView(d) With {.RowFilter = "[WhichList] = 3"}
ListBox3.DisplayMember = "ShowText"
ListBox4.DataSource = New DataView(d) With {.RowFilter = "[WhichList] = 4"}
ListBox4.DisplayMember = "ShowText"
End Sub
Private Sub ListBoxX_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick, ListBox2.DoubleClick, ListBox3.DoubleClick
DirectCast(DirectCast(sender, ListBox).SelectedItem, DataRowView).Row("WhichList") = 4
End Sub
Run the program and double click various items in various listboxes
I like the approach by Caius Jard. For two forms, you'd have to make that DataTable accessible to both forms. Then you'd use the "WhichList" column to track whether the data should appear in frm1 or frm2. You could use another column to track which list each item belonged to as well. It'd definitely work.
In lieu of that, however, here is how to move all selected items using a similar approach to what you already have:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' MOVE all selected items from lst1, lst2 and lst3 in frm1 to the same named controls in frm2:
Dim ListBoxes() As ListBox = {lst1, lst2, lst3}
For Each lb As ListBox In ListBoxes
' Get a reference to the control in frm2:
Dim lbOther As ListBox = frm2.Controls.Find(lb.Name, True).FirstOrDefault
If Not IsNothing(lbOther) Then
' Make a list from all the selected indices in each ListBox
Dim indices As New List(Of Integer)(lb.SelectedIndices.Cast(Of Integer))
' Add those items to frm2
For Each i As Integer In indices
lbOther.Items.Add(lb.Items(i))
Next
' Reverse the list so we can delete the indices without messing things up:
indices.Reverse()
For Each i As Integer In indices
lb.Items.RemoveAt(i)
Next
End If
Next
End Sub
I want to show the last clicked item on my ListBox that has multi-select. It only shows the first item on the list selected when I use the following:
Textbox1.text = listbox1.text
I think your only option would be to store a list of the selected indices and add/remove to/from it whenever the selection changes.
Something like this should do the job (assuming WinForms):
Private selectedIndices As New List(Of Integer)
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
' Add the newly selected items.
selectedIndices.AddRange(
ListBox1.SelectedIndices.Cast(Of Integer).
Where(Function(i) Not selectedIndices.Contains(i)))
' Remove the unselected items.
selectedIndices.RemoveAll(Function(i) Not ListBox1.SelectedIndices.Contains(i))
' Update the TextBox text. You can move this code to a different method
' if you want to trigger it using a button or something.
If selectedIndices.Count = 0 Then
TextBox1.Text = String.Empty
Else
Dim lastIndex As Integer = selectedIndices.Last()
TextBox1.Text = ListBox1.GetItemText(ListBox1.Items(lastIndex))
End If
End Sub
See it in action:
I'm trying to set the length of a Combo Box control in the most efficient way possible. By length, I mean the number of items in the items collection of the Combo Box control.
This is the best attempt I have:
Dim cboNew As New ComboBox
For i As Integer = 0 To cboSelection.Items.Count - 1
cboNew.Items.Add(cboSelection.Items(i))
Next
cboSelection is another Combo Box control I have, I am pretty much trying to set the length of cboSelection to cboNew with one line of code (If cboSelection has 5 items, then set cboNew to have 5 items). I feel as if I have done this before, but have forgotten how.
If you are willing to use the DataSource property, you could do something like this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ComboBox1.DataSource = New String() {"tony", "bruce", "clark"}
ComboBox2.DataSource = ComboBox1.DataSource
End Sub