Get items and index of dynamic comboBox in VB.NET - vb.net

I have created a list of eight dynamic comboBoxes through the function combox1Gen() and then i have loaded items to them from a text file of values through function loadComboboxItems(). On every respective comboBox's item selection i need to display the value and its index. what code should in put inside ComboTName_SelectedIndexChanged()?
One more issue is there. My comboBoxes with items get loaded very slowly in a hanging way. whats wrong with my code?
My code is below:
Public ComboBoxesTname As New List(Of ComboBox)
Dim i As Integer = 0
Do While i <= 7
Combo1Gen(i)
i = i + 1
Loop
loadComboboxItems()
Private Function Combo1Gen(ByVal n As Integer) As Boolean
Try
Dim newCombo As New ComboBox
With newCombo
.Name = "MyComboBox1" & n.ToString
.Left = 110
.Top = 120 + (52 * n) + 20
.Width = 180
.Height = 20
.Visible = True
End With
ComboBoxesTname.Add(newCombo)
GroupBox1.Controls.Add(newCombo)
GroupBox1.AutoSize = True
AddHandler newCombo.SelectedIndexChanged, AddressOf ComboTName_SelectedIndexChanged
Return True
Catch ex As Exception
MessageBox.Show(ex.ToString)
Return False
End Try
End Function
Private Function loadComboboxItems() As Boolean
Try
Dim listT As New List(Of String)()
listT = ReadVars.readVars(GetFolderPath.GetFolderPath("\vars\"), "items.txt")
For i = 0 To ComboBoxesTname.Count - 1
ComboBoxesTname(i).Items.AddRange(listT.ToArray)
Next
Return True
Catch ex As Exception
Debug.WriteLine(ex.ToString)
MessageBox.Show("Error: " & Err.ToString)
Return False
End Try
Return False
End Function
Private Sub ComboTName_SelectedIndexChanged()
End Sub

I am not sure exactly what you want to do in SelectIndexChanged but I showed how to get the values from the combo that was clicked.
See comments and explanations in line.
Public ComboBoxesTname As New List(Of ComboBox)
Private Sub LoadCombos()
For i = 0 To 7
Combo1Gen(i)
Next
loadComboboxItems()
End Sub
'Since you never use the return value I changed this to a Sub
Private Sub Combo1Gen(ByVal n As Integer)
Dim newCombo As New ComboBox
With newCombo
.Name = "MyComboBox1" & n.ToString
.Left = 110
.Top = 10 + (52 * n) + 20
.Width = 180
.Height = 20
.Visible = True
End With
ComboBoxesTname.Add(newCombo)
GroupBox1.Controls.Add(newCombo)
GroupBox1.AutoSize = True
AddHandler newCombo.SelectedIndexChanged, AddressOf ComboTName_SelectedIndexChanged
End Sub
'Since I don't have access to ReadVars I created an arbitrary array to test
Private listT As String() = {"Mathew", "Mark", "Luke", "John"}
'You should have readVars return an array of strings
'Create this once as a Form level variable so you don't have to read the file over and over
'Private listT As String() = ReadVars.readVars(GetFolderPath.GetFolderPath("\vars\"), "items.txt")
'Since you never use the return value I changed this to a Sub
Private Sub loadComboboxItems()
For i = 0 To ComboBoxesTname.Count - 1
ComboBoxesTname(i).Items.AddRange(listT)
Next
End Sub
'Added the appropriate parameters
Private Sub ComboTName_SelectedIndexChanged(sender As Object, e As EventArgs)
'Cast sender to a ComboBox so we can use the Properties of a ComboBox
Dim Combo = DirectCast(sender, ComboBox)
Dim Name = Combo.Name
Dim Item = Combo.SelectedItem
MessageBox.Show($"The selected item in {Name} is {Item}")
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadCombos()
End Sub
EDIT
In response to your question in comments. I added a Function and a few changes to ComboTName_SelectedIndexChanged
Private Sub ComboTName_SelectedIndexChanged(sender As Object, e As EventArgs)
'Cast sender to a ComboBox so we can use the Properties of a ComboBox
Dim Combo = DirectCast(sender, ComboBox)
Dim Name = Combo.Name
Dim N As Integer = GetValueOfN(Name)
Dim Item = Combo.SelectedItem
MessageBox.Show($"The selected item in {Name} is {Item} The number of the combo cox is {N}")
End Sub
Private Function GetValueOfN(ComboName As String) As Integer
Dim NumString = ComboName.Substring(ComboName.IndexOf("1") + 1)
Return CInt(NumString)
End Function

Related

Exporting CSV from ListView in VB.NET

i am having a bit of issue with exporting my data from a List-view in VB.NET i have included screenshots of what i am seeing basically i want to see only the Values in my csv file when i export it,
as you can see i am seeing what the List-box is showing, those values are coming from the List View Before Export. also i need the export to be in 1 column not rows as shown
any help would be great..
''''
Imports System.IO
Imports System.IO.StreamReader
Imports System.IO.StreamWriter
Imports System.Data.DataSet
Public Class Form1
Private Sub startcol_Click(sender As Object, e As EventArgs) Handles startcol.Click
Timer1.Enabled = True
End Sub
Private Sub stopcol_Click(sender As Object, e As EventArgs) Handles stopcol.Click
Timer1.Enabled = False
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Const MIN As Double = 5.0
Const MAX As Double = 400.0
Const DEC_PLACES As Integer = 2
Dim rnd As New Random
Dim list As Integer()
'Generate a random number X where MIN <= X < MAX and then round to DEC_PLACES decimal places.
Dim dbl As Double = Math.Round(rnd.NextDouble() * (MAX - MIN) + MIN, DEC_PLACES)
weight.Text = dbl
Dim newItem As New ListViewItem(weight.Text)
newItem.SubItems.Add(weight.Text)
'newItem.SubItems.Add(TextBox3.Text)
ListBox1.Items.Add(newItem)
ListView1.Items.Add(newItem)
rowcnt.Text = ListView1.Items.Count
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Timer1.Enabled = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' ExportDatasetToCsv(List)
'WriteToTextFile()
Me.DoSave()
End Sub
Private Sub DoSave()
Dim SFD As New SaveFileDialog()
Try
With SFD
.AddExtension = True
.CheckPathExists = True
.CreatePrompt = False
.OverwritePrompt = True
.ValidateNames = True
.ShowHelp = True
.DefaultExt = "txt"
.Filter = _
"CSV Files (*.csv)|*.csv|" & _
"All files|*.*"
.FilterIndex = 1
If .ShowDialog() = Windows.Forms.DialogResult.OK Then
Me.DoSaveItems(.FileName)
End If
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Exclamation, Me.Text)
End Try
End Sub
' save All values from ListView1
Private Sub DoSaveItems(ByVal fileName As String)
If fileName Is Nothing = False Then
If fileName.Length > 0 Then
Using writer As New System.IO.StreamWriter(fileName)
For Each currentItem As Object In Me.ListView1.Items
writer.Write(currentItem.ToString() & ",")
Next
End Using
End If
End If
End Sub
Public Function ExportListViewToCSV(ByVal filename As String, ByVal lv As ListView) As Boolean
Try
' Open output file
Dim os As New StreamWriter(filename)
' Write Headers
For i As Integer = 0 To lv.Columns.Count - 1
' replace quotes with double quotes if necessary
os.Write("""" & lv.Columns(i).Text.Replace("""", """""") & """,")
Next
os.WriteLine()
' Write records
For i As Integer = 0 To lv.Items.Count - 1
For j As Integer = 0 To lv.Columns.Count - 1
os.Write("""" & lv.Items(i).SubItems(j).Text.Replace("""", """""") + """,")
Next
os.WriteLine()
Next
os.Close()
Catch ex As Exception
' catch any errors
Return False
End Try
Return True
End Function
Public Sub TestExportToCSV()
Dim dlg As New SaveFileDialog
dlg.Filter = "CSV files (*.CSV)|*.csv"
dlg.FilterIndex = 1
dlg.RestoreDirectory = True
If dlg.ShowDialog = Windows.Forms.DialogResult.OK Then
If ExportListViewToCSV(dlg.FileName, ListView1) Then
Process.Start(dlg.FileName)
End If
End If
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
'TestExportToCSV()
End Sub
End Class
''''
As you haven't shown us your code, we can't tell you how to modify it specifically. In general though, you can treat the ListView somewhat like a 2D array, looping through the rows and the columns to get the data. That means that you could output the data to a CSV like this:
Using writer As New StreamWriter(filePath)
For rowIndex = 0 To myListView.Items.Count - 1
Dim item = myListView.Items(rowIndex)
'Write a line break before all but the first line.
If rowIndex > 0 Then
writer.WriteLine()
End If
For columnIndex = 0 To myListView.Columns.Count - 1
Dim subItem = item.SubItems(columnIndex)
'Write a field delimiter before all but the first field.
If columnIndex > 0 Then
write.Write(",")
End If
writer.Write(subItem.Text)
Next
Next
End Using
That's the old-school way. There are more succinct options, especially with the advent of LINQ:
File.WriteAllLines(filePath,
myListView.Items.
Cast(Of ListViewItem)().
Select(Function(item) String.Join(",",
item.SubItems.
Cast(Of ListViewItem.ListViewSubItem)().
Select(Function(subItem) subItem.Text))))
EDIT:
If you want to include the column headers then you can modify the above code like so:
Using writer As New StreamWriter(filePath)
For columnIndex = 0 To myListView.Columns.Count - 1
Dim column = myListView.Columns(columnIndex)
'Write a field delimiter before all but the first field.
If columnIndex > 0 Then
writer.Write(",")
End If
writer.Write(column.Text)
Next
For rowIndex = 0 To myListView.Items.Count - 1
Dim item = myListView.Items(rowIndex)
'Write a line break before each line.
writer.WriteLine()
For columnIndex = 0 To myListView.Columns.Count - 1
Dim subItem = item.SubItems(columnIndex)
'Write a field delimiter before all but the first field.
If columnIndex > 0 Then
writer.Write(",")
End If
writer.Write(subItem.Text)
Next
Next
End Using
File.WriteAllLines(filePath,
myListView.Items.
Cast(Of ListViewItem)().
Select(Function(item) String.Join(",",
item.SubItems.
Cast(Of ListViewItem.ListViewSubItem)().
Select(Function(subItem) subItem.Text))).
Prepend(String.Join(",",
myListView.Columns.
Cast(Of ColumnHeader)().
Select(Function(header) header.Text))))

Shuffle the contents of Text Boxes

I'm trying to get 10 different inputs in TextBoxes to be displayed in a randomized order.
I split 2 processes to make it easier to understand:
Button puts numbers in random orders from 1-10(works)
Button should replace the numbers with the contents of the TextBoxes(doesn't work)
Here is the GUI
/ Here is the code:
Public tblRandom As New DataTable
Private Sub btnRandom_Click(sender As Object, e As EventArgs) Handles btnGo.Click
Dim r As New Random
Dim tblRandom As New DataTable
tblRandom.Columns.Add("Order")
tblRandom.Constraints.Add("pk", tblRandom.Columns(0), True)
While tblRandom.Rows.Count < 10
Dim newrow As Object = r.Next(10) + 1
Try
tblRandom.Rows.Add(CStr(newrow))
Catch ex As Exception
End Try
End While
dgvRandom.DataSource = tblRandom
End Sub
Private Sub btnReplace_Click(sender As Object, e As EventArgs) Handles btnReplace.Click
For Each row As DataGridViewRow In dgvRandom.Rows
For Each cell As DataGridViewCell In row.Cells
If cell.Value IsNot Nothing Then
Dim i As Integer = 0
While i < 10
i += 1
If cell.Value.ToString = i Then
cell.Value = ActiveControl.Tag(i)
End If
End While
End If
Next
Next
dgvRandom.DataSource = tblRandom
End Sub
End Class
My understanding of your goal here is to take the text in 10 textboxes and shuffled their content. The DataGrid seems to be a temporary location that you're using during the shuffle.
There's a much easier way that avoids all that. Try this code:
Private _random = New Random()
Private Sub BtnRandom_Click(sender As Object, e As EventArgs) Handles btnRandom.Click
Dim tbs As TextBox() = {TextBox1, TextBox2, TextBox3, TextBox4, TextBox5, TextBox6, TextBox7, TextBox8, TextBox9, TextBox10}
Dim text = tbs.Select(Function(tb) tb.Text).OrderBy(Function(t) _random.Next()).ToList()
For Each x In tbs.Zip(text, Function(tb, t) New With {.tb = tb, .t = t})
x.tb.Text = x.t
Next
End Sub
That's it. Job done.
If you still need the DataGrid it would be easy to add a further line just after the x.tb.Text = x.t that adds the content of x.t to the grid.
For the first part you can do:
Public tblRandom As DataTable
Private ReadOnly rand As New Random
Private Sub btnRandom_Click(sender As Object, e As EventArgs) Handles btnRandom.Click
tblRandom?.Dispose()
tblRandom = New DataTable
tblRandom.Columns.Add("Order")
tblRandom.Constraints.Add("pk", tblRandom.Columns(0), True)
Dim nums As New List(Of Integer)
While nums.Count < 10
Dim num = rand.Next(1, 11)
If Not nums.Contains(num) Then
nums.Add(num)
End If
End While
nums.ForEach(Sub(n) tblRandom.Rows.Add(n))
dgvRandom.DataSource = tblRandom
End Sub
As for the second part, you just need to do:
Private Sub btnReplace_Click(sender As Object, e As EventArgs) Handles btnReplace.Click
For Each row As DataRow In tblRandom.Rows
'Assuming the text boxes are hosted by the Form.
Dim txt = Me.Controls.OfType(Of TextBox).
Where(Function(x) x.Tag?.ToString = row(0).ToString).
FirstOrDefault
If txt IsNot Nothing Then
row(0) = txt.Text
End If
Next
tblRandom.AcceptChanges()
End Sub
You are getting the tag from the ActiveControl
cell.Value = ActiveControl.Tag(i)
but as you've just clicked the Replace button, isn't that the active control?

Add Event to Picture Box dynamically vb.net

I'm trying to add pictureboxes dynamically in vb.net.
If i play with the vars, changing the "i" value i can add the images and the event to the last picturebox created (i can only click the last images).
But when i use the code below, it says the there's something out of boundaries ( Index outside the bounds of the matrix ).
What am i doing wrong? Tks
Imports System.IO
Public Class FormMain
Dim Path1 As String = Path.GetDirectoryName(Application.ExecutablePath) & "\Source\Images\1.png"
Dim Path2 As String = Path.GetDirectoryName(Application.ExecutablePath) & "\Source\Images\2.png"
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CreateImages()
End Sub
Dim i As Integer
Dim Logo(i) As PictureBox
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
For i = 0 To i - 1
Logo(i) = New PictureBox
Logo(i).Name = "Image" + Str(i)
Panel1.Controls.Add(Logo(i))
Logo(i).Image = Image.FromFile(Path1)
Logo(i).SizeMode = PictureBoxSizeMode.StretchImage
AddHandler Logo(i).Click, AddressOf _Click
Next
End Sub
'------ADD EVENT----
Dim IsImageSelected(i) As Boolean
Private Sub _Click(ByVal sender As Object, ByVal e As EventArgs)
If IsImageSelected(i) = False Then
Logo(i).Image = Image.FromFile(Path2)
IsImageSelected(i) = True
Else
Logo(i).Image = Image.FromFile(Path1)
IsImageSelected(i) = False
End If
End Sub
----EDIT----
I just changed the var declaration to inside of the function:
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
Dim Logo(i) As PictureBox
For i = 0 To i - 1
Logo(i) = New PictureBox
Logo(i).Name = "Image" + Str(i)
Panel1.Controls.Add(Logo(i))
Logo(i).Image = Image.FromFile(Path1)
Logo(i).SizeMode = PictureBoxSizeMode.StretchImage
AddHandler Logo(i).Click, AddressOf _Click
Next
End Sub
Now it creates the images the way i want, but i can't access the pictureboxes in the event. Help?
Don't use an array, use a List(Of PictureBox) instead. You could also store the selected state in the Tag() of the PictureBox. To get a reference to the PictureBox that was clicked, cast the Sender parameter. All together it would look something like this:
Private Logo As New List(Of PictureBox)
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
For i = 0 To i - 1
Dim pb As New PictureBox
pb = New PictureBox
pb.Tag = False ' <-- initial not selected state
pb.Name = "Image" + Str(i)
Panel1.Controls.Add(pb)
pb.Image = Image.FromFile(Path1)
pb.SizeMode = PictureBoxSizeMode.StretchImage
AddHandler pb.Click, AddressOf _Click
Logo.Add(pb)
Next
End Sub
Private Sub _Click(ByVal sender As Object, ByVal e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim selected As Boolean = DirectCast(pb.Tag, Boolean)
If selected = False Then
pb.Image = Image.FromFile(Path2)
Else
pb.Image = Image.FromFile(Path1)
End If
pb.Tag = Not selected ' toggle selected state
End Sub

Datagridview strange display error on init

upon initialization of my UI i get the following very strange behavior regarding to the drawing of the datagridview:
Basically, expect the first row header and the column headers (which i did not include in the pic) it looks like the DGV prints what is on the Screen "behind" his application.
What the hell is this and does anyone know a way to fix it?
Code of Container:
Public Class DGVControl
Dim dt As DataTable
Public Sub init()
dt = New DataTable
Dim arr(ldfAttributes.Count - 1) As String
Dim cms As New ContextMenuStrip
Dim i As Integer = 0
For Each att As String In Attributes.Keys
Dim cmsitem As New ToolStripMenuItem
dt.Columns.Add(att, GetType(String))
cmsitem.Name = att
cmsitem.Text = att
cmsitem.Owner = cms
cmsitem.CheckOnClick = True
cmsitem.Checked = my.Settings.shownColumns.Contains(att)
AddHandler cmsitem.CheckedChanged, AddressOf showOrHideColumn
cms.Items.Add(cmsitem)
arr(i) = "No Data"
i += 1
Next
For i = 1 To my.settings.anzEntries
dt.Rows.Add(arr)
Next
MainDGV.DataSource = dt
MainDGV.ContextMenuStrip = cms
For Each attName as String In Attributes.key
showOrHideColumn(cms.Items(attName), New EventArgs())
Next
MainDGV.RowHeadersWidth = 90
MainDGV.RowTemplate.Height = 40
MainDGV.RowHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.RowHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.ColumnHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.ColumnHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.BackgroundColor = Color.White
End Sub
Private Sub showOrHideColumn(sender As Object, e As EventArgs)
Dim cmsitem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
MainDGV.Columns(cmsitem.Name).Visible = cmsitem.Checked
End Sub
'taken from: http://stackoverflow.com/questions/710064/adding-text-to-datagridview-row-header
Private Sub nameRowHeaders(sender As Object, e As EventArgs) Handles MainDGV.DataBindingComplete
Dim dgv As DataGridView = CType(sender, DataGridView)
For i As Integer = 0 To dgv.RowCount - 1
dgv.Rows(i).HeaderCell.Value = ("Entry " &(i+1).toString())
Next
End Sub
End Class
EDIT:
As soon as you once select a row, all cells will be displayed in the right way until you restart the application

Computer Click Event Visual Basic

How do I create a random click event driven by the computer? Where the user doesn't get to choose where it clicks?
I have created a table that is 5 buttons wide and 5 buttons tall, and created a click event where the user clicks on a button and the random number value is added onto their score.
Dim RandomNumbers = Enumerable.Range(0, 100).ToList()
Dim RandomNumber As New Random()
For Me.TableColunm = 0 To 4 Step 1
For Me.TableRow = 0 To 4 Step 1
Dim TemporaryNumber = RandomNumbers(RandomNumber.Next(0, RandomNumbers.Count))
RandomNumbers.Remove(CInt(TemporaryNumber))
TableButtons = New Button()
With TableButtons
.Name = "TextBox" & TableColunm.ToString & TableRow.ToString
.Text = TemporaryNumber.ToString
.Width = CInt(Me.Width / 4)
.Left = CInt(TableColunm * (Me.Width / 4))
.Top = TableRow * .Height
'.Tag = TemporaryNumber
AddHandler TableButtons.Click, AddressOf UserTableButtonClickEvent
End With
GameScreen.Controls.Add(TableButtons)
Next TableRow
Next TableColunm
Catch ex As Exception
MsgBox(ex.StackTrace & vbCrLf & "index1= " & TableColunm & vbCrLf & "index2= " & TableRow)
End Try
Private Sub UserTableButtonClickEvent(sender As Object, e As EventArgs)
CType(sender, Button).BackColor = Color.LightSteelBlue
OverAllScoreInteger += CInt(CType(sender, Button).Tag)
GameScreen.UserScoreBox.Text = OverAllScoreInteger.ToString
Dim TableButton As Button = CType(sender, Button)
TableButton.Text = "#"
TableButton.Enabled = False
End Sub
How do I make another event like this but at random?
Enumerate all controls in the GameScreen.Controls collection and add them to a temporary list if they are a button. Then generate a random number in the range of the length of the list and click the button with this index:
Dim TempButtonList As New List(Of Button)
For Each c as Control in GameScreen.Controls
If TypeOf(c) Is Button Then TempButtonList.Add(CType(c, Button))
Next
Dim Rnd as New Random
TempButtonList(rnd.Next(0, TempButtonList.Count-1)).PerformClick()
The PerformClick() method does exactly the same as if you would click that button with your mouse. The If in the loop makes sure you only add buttons in the controls collection, because there may of course be other controls inside.
Complete example
It's probably easier that way (Add a FlowLayoutPanel with Size=275; 275 and two Labels to a Form):
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Rnd As New Random
For i = 1 To 25
Dim b As New Button With {.Text = Rnd.Next(0, 100)}
b.Width = 40
b.Height = 40
FlowLayoutPanel1.Controls.Add(b)
AddHandler b.Click, AddressOf b_hndl
Next
End Sub
Private MyScore As Integer = 0
Private HisScore As Integer = 0
Dim Zug As Boolean = True
Private Sub b_hndl(sender As Object, e As EventArgs)
Dim ThisB As Button = CType(sender, Button)
Dim CurrScore As Integer = CInt(ThisB.Text)
Dim CurrZug As Boolean = Zug
Zug = Not Zug
ThisB.Enabled = False
ThisB.Text = "#"
If CurrZug Then
MyScore += CurrScore
Label1.Text = MyScore.ToString
ComputerMove()
Else
HisScore += CurrScore
Label2.Text = HisScore.ToString
End If
End Sub
Private Sub ComputerMove()
Dim TempButtonList As New List(Of Button)
For Each c As Control In FlowLayoutPanel1.Controls
If TypeOf (c) Is Button Then
Dim thisb As Button = CType(c, Button)
If thisb.Enabled Then TempButtonList.Add(thisb)
End If
Next
If TempButtonList.Count = 0 Then Exit Sub
Dim Rnd As New Random
TempButtonList(Rnd.Next(0, TempButtonList.Count - 1)).PerformClick()
End Sub
End Class
The Dim Zug As Boolean = True determines if the player or the computer is currently in queue to select a button. It is switched on every button press, so the players take turns. The ComputerMove function is executed after the player clicked a button.