Adding a variable to a listBox in VB.net Windows Form - vb.net

I am making a dvd database system in windows form and trying to display the dvd's entered by a user. Then display the Title, Director and Genre in 3 separate listBoxes.
When the user enters the information through 3 separate text boxes, the information is stored in a structure I made called TDvd. This means I can call for example dvd.Title or dvd.Director. I also use the variable index to add this information to an array I made called Dvd(100) (just a random number I used to test).
Here is the code I currently have for adding the items to the ListBox:
For i = 1 To noOfAddedDvds
lstTitle.Items.Add(dvd(i).Title)
lstDirector.Items.Add(dvd(i).Director)
lstGenre.Items.Add(dvd(i).Genre)
Next
The variable NoOfDvdsAdded is just a way of keeping track of the number of dvd's the user has already entered.
I run this and enter the Title, Director and Genre, but when I try and display this information across the 3 listboxes, I get the error:
An unhandled exception of type 'System.ArgumentNullException' occurred in System.Windows.Forms.dll
Public Class Form1
Structure TDvd
Dim Title As String
Dim Director As String
Dim Genre As String
End Structure
Dim dvd(100) As TDvd
Dim index As Integer = 0
Dim noOfAddedDvds As Integer
Private Sub btnAddToDatabase_Click(sender As Object, e As EventArgs) Handles btnAddToDatabase.Click
If txtDirector.Text <> "" Or txtGenre.Text <> "" Or txtTitle.Text <> "" Then
txtTitle.Text = dvd(index).Title
txtDirector.Text = dvd(index).Director
txtGenre.Text = dvd(index).Genre
index += 1
noOfAddedDvds += 1
End If
End Sub
Private Sub btnDisplayDatabase_Click(sender As Object, e As EventArgs) Handles btnDisplayDatabase.Click
Dim i As Integer
For i = 0 To noOfAddedDvds
MessageBox.Show(index & ", " & i)
lstTitle.Items.Add(dvd(i).Title)
lstDirector.Items.Add(dvd(i).Director)
lstGenre.Items.Add(dvd(i).Genre)
MessageBox.Show(index & ", " & i)
Next
End Sub
End Class

According to the documentation, an ArgumentNullException is thrown by the Add() method if the argument passed to it is null. (Or Nothing in VB.) So one of these is Nothing at runtime:
dvd(i).Title
dvd(i).Director
dvd(i).Genre
You'll have to debug to determine which. It would seem that the error is because you're starting your iteration at 1 instead of 0, I would think it should be:
For i = 0 To noOfAddedDvds - 1
So when you get to the index of noOfAddedDvds in your collection, that element will be an uninitialized struct with Nothing strings.
You'll definitely want to fix the iteration (indexes start at 0). Additionally, you may also benefit from initializing the String properties in your struct to String.Empty internally. Depends on whether you want similar errors to manifest as an exception or as an empty record. Sometimes the latter makes the problem more obvious since at runtime you'd see that your output started on the second record.

Just a few pointers...
The Items collection on the ListBox is actually 0 indexed, by which I mean that instead of going "1,2,3", it actually goes (0,1,2).
That's what your problem is.
Hint - think about perhaps using a List instead of an array as well... (for dvd)

Your thing cries out for being rewritten in OO form:
Friend DVDGenres
Undefined
Comedy
Action
Adventure
Sci-Fi
End Enum
Friend Class DVD
Public Property Title As String
Public Property Director As String
Public Property Genre As DVDGenres
Public Sub New
Title = ""
Director = ""
Genre = DVDGenres.Undefined
' other stuff too
End Sub
Public Overrides Function ToString As String
Return Title
End Sub
End Class
Now something to store them in. Arrays went out with Rubik's Cubes, so a List:
Private myDVDs As New List(of DVD)
A list and a class can do what arrays and structures can without the headaches. Add a DVD:
Dim d As New DVD
d.Name = TextBoxName.Text
d.Director = TextBoxDir.Text
d.Genre = comboboxGenre.SelectedItem
' add to the container:
myDVDs.Add(d)
Display all the DVDs in a ListBox to pick from:
AllDVDsLB.DataSource = myDVDs
AllDVDsLB.DisplayMember = "Title"
This will set your list as the datasource for the listbox. Whatever is in the List is automatically displayed without copying data into the Items collection. Then, say from selectedindex changed event, display the selected item details to some labels:
Label1.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Title
Label2.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Director
Label3.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Genre.ToString
Iterate to do something like what is in the Question:
For Each d As DVD in myDVDs ' CANT run out of data
lstTitle.Items.Add(d.Title)
lstDirector.Items.Add(d.Director)
lstGenre.Items.Add(d.Genre.ToString)
Next
Or iterate and reference with an Int32:
For n As Integer = 0 To myDVDs.Count - 1
lstTitle.Items.Add(myDVDs(n).Title)
' etc
Next n
HTH

Related

unable to add items to a list in VB.NET

Good morning,
so i have received this homework for the summer where i have to create a program to store a list of movies and display them, but the problem is that there isn't a defined number of movie so i can't use the constant method i've always used, so i tried doing that with variables instead, but whenever i press the input button twice the app crashes and i get the error "Index over the matrix limits"
Here's the code in the module
Module Module1
Public Structure Film
Public Titolo As String
Public Autore As String
Public Incasso As Integer
Public Nazionalita As String
End Structure
Public i As Integer = 0
Public Flm(i) As Film
End Module
And here's the input part
Public Class frmInput
Private Sub btnInserisci_Click(sender As Object, e As EventArgs) Handles btnInserisci.Click
If IsNumeric(txtIncasso.Text) = False Then
MsgBox("L'incasso deve essere un valore numerico", MsgBoxStyle.Exclamation, "Attenzione")
ElseIf txtTitolo.Text = "" Or txtAutore.Text = "" Or txtNazionalita.Text = "" Then
MsgBox("Uno o piĆ¹ valori sono vuoti", MsgBoxStyle.Exclamation, "Attenzione")
Else
Flm(i).Titolo = txtTitolo.Text
Flm(i).Autore = txtAutore.Text
Flm(i).Incasso = txtIncasso.Text
Flm(i).Nazionalita = txtNazionalita.Text
i += 1
End If
End Sub
End Class
You should use a List(Of Film) to store the inputs received.
A generic List like that has no practical limits and can grow while you add elements to it
Public Flm As List(Of Film) = new List(Of Film)
....
Else
Dim f as Film = new Film()
f.Titolo = txtTitolo.Text
f.Autore = txtAutore.Text
f.Incasso = txtIncasso.Text
f.Nazionalita = txtNazionalita.Text
Flm.Add(f)
End If
A List(Of Film) could be used like it was an array
For x As Integer = 0 To Flm.Count -1 Step 1
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & Flm(x).Titolo)
.....
Next
And of course you can iterate over it using a simpler foreach
For Each Film f in Flm
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & f.Titolo)
.....
Next
Although others have mentioned using List, which would probably be appropriate, you also mentioned it was a homework task, so maybe you need, or have to, use the more traditional arrays as you have shown. Bearing this in mind, and also to let you know what your problem is. You are incrementing i but not the array.
Public i As Integer = 0
Public Flm(i) As Film
Thus, Flm is 0 to 0, one element.
You add to this, all is OK.
You increment i, good, i += 1
However, you don't then increment the array, Flm(). Incrementing i doesn't automatically increment the array, Flm().
You need to use: ReDim Preserve
Thus... Change:
Else
Flm(i).Titolo = txtTitolo.Text
to:
Else
ReDim Preserve Flm(i)
Flm(i).Titolo = txtTitolo.Text
Lastly, IsNumeric and MsgBox are remnants of the VB6 days, there are vb.net equivalents. Also, using i as a global/public variable is really not good. It's very common, standard, to use i in all local subroutines and functions for little loops etc, it gets used and lost. If you look at almost all examples of code, you'll see i being used as the integer counter.

Visual Basic: loaded parallel list boxes with text file substrings, but now items other than lstBox(0) "out of bounds"

The text file contains lines with the year followed by population like:
2016, 322690000
2015, 320220000
etc.
I separated the lines substrings to get all the years in a list box, and all the population amounts in a separate listbox, using the following code:
Dim strYearPop As String
Dim intYear As Integer
Dim intPop As Integer
strYearPop = popFile.ReadLine()
intYear = CInt(strYearPop.Substring(0, 4))
intPop = CInt(strYearPop.Substring(5))
lstYear.Items.Add(intYear)
lstPop.Items.Add(intPop)
Now I want to add the population amounts together, using the .Items to act as an array.
Dim intPop1 As Integer
intPop1 = lstPop.Items(0) + lstPop.Items(1)
But I get an error on lstPop.Items(1) and any item other than lstPop.Items(0), due to out of range. I understand the concept of out of range, but I thought that I create an index of several items (about 117 lines in the file, so the items indices should go up to 116) when I populated the list box.
How do i populate the list box in a way that creates an index of list box items (similar to an array)?
[I will treat this as an XY problem - please consider reading that after reading this answer.]
What you are missing is the separation of the data from the presentation of the data.
It is not a good idea to use controls to store data: they are meant to show the underlying data.
You could use two arrays for the data, one for the year and one for the population count, or you could use a Class which has properties of the year and the count. The latter is more sensible, as it ties the year and count together in one entity. You can then have a List of that Class to make a collection of the data, like this:
Option Infer On
Option Strict On
Imports System.IO
Public Class Form1
Public Class PopulationDatum
Property Year As Integer
Property Count As Integer
End Class
Function GetData(srcFile As String) As List(Of PopulationDatum)
Dim data As New List(Of PopulationDatum)
Using sr As New StreamReader(srcFile)
While Not sr.EndOfStream
Dim thisLine = sr.ReadLine
Dim parts = thisLine.Split(","c)
If parts.Count = 2 Then
data.Add(New PopulationDatum With {.Year = CInt(parts(0).Trim()), .Count = CInt(parts(1).Trim)})
End If
End While
End Using
Return data
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim srcFile = "C:\temp\PopulationData.txt"
Dim popData = GetData(srcFile)
Dim popTotal = 0
For Each p In popData
lstYear.Items.Add(p.Year)
lstPop.Items.Add(p.Count)
popTotal = popTotal + p.Count
Next
' popTotal now has the value of the sum of the populations
End Sub
End Class
If using a List(Of T) is too much, then just use the idea of separating the data from the user interface. It makes processing the data much simpler.

Null Reference Exception on Dictionary

I know that a null reference exception generally occurs when accessing an item in a collection that doesn't exist. However, in this case, one is being thrown despite me explicitly creating this item mere lines beforehand. I have scoured my code and cannot find the source of this error (the code is very basic ATM as I have just begun the process of restructuring a solution made for a client.
Background info:
PhotoJobs is a custom class that holds all of the properties of a specific manufacturing Job
These are all held in a Public Dictionary(of string, PhotoJob) which is held in the MainForm class.
A ("temp") photojob is created within this dictionary to handle the addition of new jobs as data is added (this appears to be the source of the error.
Code:
Private Sub AddJob_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MainForm.photoJobs.Add("temp", New PhotoJob())
pctBox.AllowDrop = True
End Sub
Public Sub pctbox_drop(sender As Object, e As DragEventArgs) Handles pctBox.DragDrop
Dim pics As String() = CType(e.Data.GetData(DataFormats.FileDrop), String()) 'Gets the data from the file drop
If MainForm.photoJobs("temp").imageList.Count = 0 Then
MainForm.photoJobs("temp").imageList = pics.ToList 'Gets the data from the file drop
Else
For i = 0 To MainForm.photoJobs("temp").imageList.Count - 1
If Not MainForm.photoJobs("temp").imageList.Contains(pics(i)) Then
MainForm.photoJobs("temp").imageList.Add(pics(i))
End If
Next
End If
MainForm.photoJobs("temp").photoID = CType(formatID(MainForm.photoJobs("temp").imageList(0)), String)
txtPhotoID.Text = MainForm.photoJobs("temp").photoID
Select Case MainForm.photoJobs("temp").imageList.Count
Case 0
MsgBox("Please ensure that you are dropping image files")
Case 1
lblImageNumber.Text = txtPhotoID.Text
checkBoxes(0)
Case 2
txtPhotoID.Text = txtPhotoID.Text & "(2)"
lblImageNumber.Text = txtPhotoID.Text
checkBoxes(1)
Case 3
txtPhotoID.Text = txtPhotoID.Text & "(3)"
lblImageNumber.Text = txtPhotoID.Text
checkBoxes(2)
Case 4
txtPhotoID.Text = txtPhotoID.Text & "(4)"
lblImageNumber.Text = txtPhotoID.Text
checkBoxes(3)
End Select
spinCounter.Value = 1
spinCounter.Minimum = 1
spinCounter.Maximum = MainForm.photoJobs("temp").imageList.Count
pctBox.ImageLocation = MainForm.photoJobs("temp").imageList(0)
End Sub
The error gets called on the If MainForm.photoJobs("temp").imageList.Count = 0 Then line.
On a second, minor note, is it fairly typical for clients to ask for "just one more little thing" that results in you having to make a major overhaul to an application, or have I just got unlucky? (slightly rhetorical)
Ensure that imageList is not null, as you declare a new PhotoJob but don't set any values in it.
When dealing with a NullReferenceException, you're not looking at something missing from a collection, it means you tried to access a member of a object which is null. This can sometimes be a side effect of an item not in a collection, if that collection returns null, but if a value does not exist in a Dictionary, you get a KeyNotFoundException
Please make sure that 'imageList' has 'count' property more than 0. Means just check that the list does have elements in it by executing theses lines before executing loop.
Dim pics As String() =CType(e.Data.GetData(DataFormats.FileDrop),String())
If MainForm.photoJobs("temp").imageList.Count > 0 Then
For i = 0 To MainForm.photoJobs("temp").imageList.Count - 1
If Not MainForm.photoJobs("temp").imageList.Contains(pics(i)) Then
MainForm.photoJobs("temp").imageList.Add(pics(i))
End If
Next
'Gets the data from the file drop
Else
MainForm.photoJobs("temp").imageList = pics.ToList
End If
Well this is embarrassing...
The solution was simply that I was missing new when I declared the list it used to read Public Property imageList as list(of string) can't believe I did that... Hey ho, thanks for all of your help guys.

visual basic argument null exception

I am about to admit defeat on this, I'm fairly new to VB and I am sure there is something quite basic I've managed to miss,
My problem with the following code is when the Button3_Click function is executed a "Value cannot be null. Parameter name: item" exception arises at run-time, if I forget to include the ".Name" on this line "ListBox2.Items.Add(test.Name)" then stuff still gets vomited out to the listbox so assuming there's something there,
any help?
Regards
Dan
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles
Button3.Click
Dim test As comdevice
Dim usbcoms() As comdevice = FindComs()
For Each test In usbcoms
ListBox2.Items.Add(test.Name)
Next
End Sub
Private Function FindComs() As comdevice()
Dim USBClass As New System.Management.ManagementClass("Win32_PNPEntity")
Dim USBCollection As System.Management.ManagementObjectCollection =
USBClass.GetInstances()
Dim USB As System.Management.ManagementObject
Dim temp() As comdevice
Dim n As Integer
n = 0
For Each USB In USBCollection
If USB("Name").ToString().Contains("P") Then
n += 1
End If
Next USB
ReDim temp(n)
n = 0
For Each USB In USBCollection
If USB("Name").ToString().Contains("COM") Then
temp(n).Name = USB("Name").ToString()
temp(n).DeviceID = USB("DeviceID").ToString()
End If
Next
Return temp
End Function
Private Structure comdevice
Public Name As String ' This employee's given name.
Public DeviceID As String ' This employee's family name.
End Structure
Your problems lies in the FindComs method.
The first loop search the USBCollection for devices that contains the letter P and you count them.
In the second loop, after dimensioning the return array with the number of devices found you try to fill this array with devices that contains the string COM, of course there is no relation between devices with COM and P in their name. You end up with an array bigger than the effective number of devices with COM in their name.
When the array returns, you add every slot of the array, but you have slots with NULL values and thus the error.
You can fix the problem dimensioning the array only for the devices with COM in their names
For Each USB In USBCollection
If USB("Name").ToString().Contains("COM") Then
n += 1
End If
Next USB
ReDim temp(n)
Oded's comment is the most likely cause of this failure.
An easy test is to set the Name property to some default string, like "test" in your comdevice class.
That way, the Name property will never be null and you can see if it ever gets changed.

VB 2010 array/write array to file

I'm close to getting this to work, but currently can't get any output to display in the listbox. I had it working, but needed to move some things around to get the join function to work.
In my program, a user enters input into a textbox and an array is displayed in a listbox based on what they type in. For example, if they type in "a", all foods (in the textfile that is connected to the program) that start with "a" will be displayed.
When there is output, I need to find a way to name this array (which is created based on what the user inputs) and join all of the items in the listbox (example: foods stacked on top of each other in the listbox will be shown at the bottom as a string).
I am posting the code that I have thus far; all of the errors that I'm getting (and potentially my logic errors) are just in the first public class until the end of the first if-next statement:
Public Class frmFoods
Dim foods() As String = IO.File.ReadAllLines("foods.txt")
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
For Each food As String In foods
smallerarray = listfoods(Letter)
lstOutput.Items.Add(Letter)
userarray = Join(smallerarray, ", ")
lstOutput.Items.Add(userarray)
Next
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
Function listfoods(ByVal letter As String) As String()
Dim foodarray(foods.Count - 1) As String
Dim counter As Integer = 0
For Each food As String In foods
If food.StartsWith(letter) Then
foodarray(counter) = food
counter += 1
End If
Next
ReDim Preserve foodarray(counter - 1)
Return foodarray
End Function
you need to save the results of the listfoods function in a dictionary or similar and associate it with a key if you want to 'Name' it, although its not clear why you need to do this
As for listing the foods starting with the particular letter, you just need to iterate your result of the function listfoods and separate each one by a comma don't you?
What you have now will create many lists of each food as you are getting the list of food beginning with a particular letter for each food.. As I understand the question you only need to do that once.
Example:
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
'get all items from the file which begin with the letter the user chose
smallerarray = listfoods(Letter)
'add that letter to the output listbox
lstOutput.Items.Add(Letter)
'join all of the elements which begin with that letter
'into a single comma separated string
userarray = Join(smallerarray, ", ")
'add that string to the output
lstOutput.Items.Add(userarray)
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
it would probably be useful for you to step through the code and see the values of the variable at each place and compare this with what you expect to see if you can see where the actual value differs from what your logically expect so you can start to identify where the issue is