Move an item from a list and remove it from the previous one in the same for each - vb.net

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

Related

Form Loads slowly in vb.net

I am currently working in ERP project on vb.net. I want to load product data in a textbox on form load. I am using autocomplete method but having a data of around 26000 the form loads slowly for 4 mins. Is there any way to avoid this or is there any way to call this function in background when the application starts?
This is my autocomplete textbox code. It works fine but it hangs alot as of the data is so large.
Private Sub pn()
Try
con = Class1.dbconn
Dim dt As New DataTable
Dim ds As New DataSet
ds.Tables.Add(dt)
Dim da As New SqlDataAdapter("select [Part Name] from
Part_Master_Download$", con)
da.Fill(dt)
Dim r As DataRow
TextBox9.AutoCompleteCustomSource.Clear()
For Each r In dt.Rows
TextBox9.AutoCompleteCustomSource.Add(r.Item(0).ToString)
Next
con.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
the properties of the textbox should be set to true for autocompletetextbox
Don't populate the AutoCompleteCustomSource in a loop. Populate an array first and then load the list in one go with a single call to AddRange:
Dim items = dt.Rows.Cast(Of DataRow)().
Select(Function(row) CStr(row(0)).
ToArray()
TextBox9.AutoCompleteCustomSource.AddRange(items)
You should find that that speeds things up considerably. If there's still a problem with performance, we can look a bit further.
EDIT: To prove my point, I just tested the following code:
Public Class Form1
Private timer As Stopwatch
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timer = Stopwatch.StartNew()
Dim rng As New Random
Dim a = Convert.ToInt32("a"c)
Dim z = Convert.ToInt32("z"c)
Dim items = Enumerable.Range(1, 26000).Select(Function(n) Convert.ToChar(rng.Next(a, z + 1)).ToString())
For Each item In items
TextBox1.AutoCompleteCustomSource.Add(item)
Next
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
MessageBox.Show(timer.Elapsed.ToString())
End Sub
End Class
and the message displayed "00:03:08.3167858", i.e. just over three minutes to load the list. I then changed the Load event handler to this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timer = Stopwatch.StartNew()
Dim rng As New Random
Dim a = Convert.ToInt32("a"c)
Dim z = Convert.ToInt32("z"c)
Dim items = Enumerable.Range(1, 26000).Select(Function(n) Convert.ToChar(rng.Next(a, z + 1)).ToString())
TextBox1.AutoCompleteCustomSource.AddRange(items.ToArray())
End Sub
so a single call to AddRange instead of calling Add in a loop, and the message was "00:00:00.0557427", i.e. just under 56 milliseconds. Is that better?
You can use paging to control the amount of returned data. Check this link for detailed examples.
Another way is to use (Task Async and await) so you won't lock your UI.
Here is a few last suggestions not related directly to the question but might help clean the code a bit:
you can skip the dataset and use the datatable directly, you don't need it for just one table.
Bind your results in the datatable to a datagridview or a combobox instead of iterating through your results and filling a textbox.
cheers

How to handle events of programatically created tools in a loop

I am creating a form builder which creates multiple tabs and on each tab will place a DataGridView linked to a dataset in a dataset array:
For Each table As DataTable In datasetInput(i).Tables
If arr_tables(i)(j).Equals(table.TableName) Then
tablename = table.TableName
Dim grid As New DataGridView
grid.DataSource = table
grid.Name = j
grid.Location = place
grid.Size = New System.Drawing.Size(734, 150)
TabPage.TabPages(i).Controls.Add(grid)
End If
Next
Note that this loop is nested within another loop that handles each tab on the form. arr_tables is a jagged array which handles which tables from the dataset I want because I do not want to pull every datatable into a DGV.
Now what I need to do is format any cell that falls in the column of name "Equation". For all cells in the "Equation" column I want to be a drop down cell with a few different options. Secondly, how can I handle a cell click event? Say any cell that falls in the column name "Input" I want to provide a MessageBox.
Normally I would have no issue doing these things if the DataGridViews weren't created within a loop. But because they are they get lost within the code and I don't know how to reference them.
Thank you!
Try this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each table As DataTable In datasetInput(i).Tables
If arr_tables(i)(j).Equals(table.TableName) Then
tablename = table.TableName
Dim grid As New DataGridView
grid.DataSource = table
grid.Name = j
grid.Location = place
grid.Size = New System.Drawing.Size(734, 150)
TabPage.TabPages(i).Controls.Add(grid)
AddHandler grid.SelectionChanged, AddressOf grid_SelectionChanged
End If
Next
End Sub
Private Sub grid_SelectionChanged(sender As Object, e As EventArgs)
' your code
End Sub

Compare the values of two listboxes and add the non-equivalent values to a third listbox

My knowledge of programming is not too extensive but I have just finished my second year of higher education in computer engineering and have taken a few low level programming courses.
In Visual Basic, I am having trouble comparing the values of two ListBox controls and putting the values that aren't the same into another ListBox.
I need to compare the items of ListBox2 to the items of ListBox1 and if there are any items in ListBox2 that are not in ListBox1, add them to ListBox3. I do not need to find the items in ListBox1 that are not in ListBox2. I cannot use a loop to compare their values based on index because these lists are of names which will be constantly added to and removed from. I also cannot sort these ListBoxes.
There was an example for C# that I found here that used LINQ (I don't really know what that is) to compare the lists and then add the result to a TextBox control. However, I need to know how to add them to a ListBox and not a TextBox.
[EDIT] The example that I have tried is this:
Dim result As List(Of String) = (From s1 As String In Me.ListBox1.Items Where Not Me.ListBox2.Items.Contains(s1) Select s1).ToList()
Me.TextBox1.Text = String.Join(Environment.NewLine, result)
Dim one As ListBox = New ListBox()
Dim two As ListBox = New ListBox()
Dim three As ListBox = New ListBox()
Dim unique As Boolean = True
For i As Integer = 0 To one.Items.Count
For j As Integer = 0 To two.Items.Count
If (one.Text = two.Text) Then
unique = False
Else
two.SelectedIndex = j
End If
Next
If (unique) Then
three.Items.Add(one.Text)
Else
one.SelectedIndex = i
unique = True
End If
Next
I believe this may be what you're looking for. What it does is compares each value in Listbox one to all values in Listbox two and if a value is seen to be a duplicate the Boolean flag unique is switched to false and the item is not added to Listbox three.
I think i found the solution:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListBox3.Items.Clear()
Dim result As List(Of String) = (From s1 As String In Me.ListBox2.Items Where Not Me.ListBox1.Items.Contains(s1) Select s1).ToList()
For Each l In result
ListBox3.Items.Add(l)
Next
End Sub
or
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim result As List(Of String) = (From s1 As String In Me.ListBox2.Items Where Not Me.ListBox1.Items.Contains(s1) Select s1).ToList()
For Each l In result
If Not ListBox3.Items.Contains(l) Then
ListBox3.Items.Add(l)
End If
Next
End Sub
Try which works best for you :)

Set Length of ComboBox

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

Delete line of structure array and update it in tab vb.net

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.