VB .Net listboxes and collections of objects - vb.net

I would like to move Item objects between the 2 following collections.
Private ItemsInRoom As New List(Of CItem)
Private Inv As New List(Of CItem)
I would like this to be done through 2 ListBoxes. 1 is the Inventory and the other is the Item list. How can I do this.
The CItem class has several members, only the Name of the item needs to be shown in the ListBox. I have been at this for hours, but I can't get anything to work. Does this explanation make sense in what I'm trying to do? If not, what else can I explain so someone might help me?

In your CItem class you need to override the ToString() function. That will get the name displayed in the listbox.
Public Class CItem
Public Overrides Function ToString() As String
Return Me.Name
End Function
'etc...
End Class

I think what you want is this:
Which is accomplished with the following code:
Option Explicit On
Public Class Form1
Private ItemsInRoom As New List(Of CItem)
Private ItemsInInv As New List(Of CItem)
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
ItemsInInv.Add(New CItem(1001, "Egret"))
ItemsInInv.Add(New CItem(1002, "Dove"))
ItemsInInv.Add(New CItem(1003, "Hawk"))
UpdateBindings()
End Sub
Public Function CheckOut(ByVal item As CItem) As Boolean
If item IsNot Nothing Then
ItemsInInv.Remove(item)
ItemsInRoom.Add(item)
Return True
End If
Return False
End Function
Public Function CheckIn(ByVal item As CItem) As Boolean
If item IsNot Nothing Then
ItemsInRoom.Remove(item)
ItemsInInv.Add(item)
Return True
End If
Return False
End Function
Public Sub UpdateBindings()
itemsInInvListBox.BeginUpdate()
itemsInInvListBox.DataSource = Nothing
itemsInInvListBox.DataSource = ItemsInInv
itemsInInvListBox.DisplayMember = "Name"
itemsInInvListBox.EndUpdate()
itemsInInvListBox.Refresh()
itemsInRoomListBox.BeginUpdate()
itemsInRoomListBox.DataSource = Nothing
itemsInRoomListBox.DataSource = ItemsInRoom
itemsInRoomListBox.DisplayMember = "Name"
itemsInRoomListBox.EndUpdate()
itemsInRoomListBox.Refresh()
End Sub
Private Sub itemsInInvListBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles itemsInInvListBox.SelectedIndexChanged
checkOutButton.Enabled = itemsInInvListBox.SelectedIndex <> -1
End Sub
Private Sub itemsInRoomListBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles itemsInRoomListBox.SelectedIndexChanged
checkInButton.Enabled = itemsInRoomListBox.SelectedIndex <> -1
End Sub
Private Sub checkOutButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles checkOutButton.Click
Dim item As CItem = CType(itemsInInvListBox.SelectedItem, CItem)
If CheckOut(item) Then
UpdateBindings()
End If
End Sub
Private Sub checkInButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles checkInButton.Click
Dim item As CItem = CType(itemsInRoomListBox.SelectedItem, CItem)
If CheckIn(item) Then
UpdateBindings()
End If
End Sub
End Class
Public Class CItem
Public Sub New(ByVal item_id As UInteger, ByVal item_name As String)
Me.m_id = item_id
Me.m_name = item_name
End Sub
Private m_name As String
Public Property Name() As String
Get
Return m_name
End Get
Set(ByVal value As String)
m_name = value
End Set
End Property
Private ReadOnly m_id As UInteger
Public ReadOnly Property ID() As UInteger
Get
Return m_id
End Get
End Property
End Class

Related

What should I add to a custom class so it works with System.Windows.Forms.Listbox.Items.Contains()..?

What should I add to a custom class so it works with System.Windows.Forms.Listbox.Items.Contains()..?
I've created a class called "FileItem" for handling filenames in ListBoxes. It works as expected, but if I try to use ListBox.Items.Contains() to prevent duplicate items from being added, nothing happens. The Contains() function never returns True.
Here's the code. Add it to a VB.Net form named frmTest with a ListBox1, Button1, and Button2. Run it and press Button1 multiple times. The duplicate warning message is never displayed.
Public Class frmTest
Private Sub frmTest_Load(sender As Object, e As EventArgs) Handles Me.Load
With ListBox1
.DisplayMember = "ShortName"
.ValueMember = "LongName"
End With
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim f As FileItem = New FileItem("C:\Windows\Notepad.exe")
If ListBox1.Items.Contains(f) Then
MsgBox("The file is already added and will be skipped.")
Else
ListBox1.Items.Add(f)
End If
f = Nothing
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim msg As String = ""
For Each item As FileItem In ListBox1.Items
msg &= item.FullName & vbCr
Next
MsgBox(msg)
End Sub
Private Class FileItem
Private ReadOnly _FullName As String
Private ReadOnly _ShortName As String
Public Sub New(ByVal FullName As String)
_FullName = FullName
If FullName.Contains("\") Then
Dim pos As Integer = FullName.LastIndexOf("\")
_ShortName = FullName.Substring(pos + 1)
End If
End Sub
Public ReadOnly Property FullName() As String
Get
Return _FullName
End Get
End Property
Public ReadOnly Property ShortName() As String
Get
Return _ShortName
End Get
End Property
Public Overrides Function ToString() As String
Return _FullName
End Function
End Class
End Class

ListChanged Event not firing?

I have a class with a bindinglist(of T) in it. The bindinglist is bound to a datagridview on my form. When items are added to the bindinglist, they show up in the datagridview however the scrollbar never changes to accommodate for the new data. I am starting to think this is because the Listchanged event isn't being fired (or properly captured by my form). I have my code set up like this:
Data Class:
Public Class data
Implements INotifyPropertyChanged
Public Sub new(byVal att1 as string, ByVal att2 as string)
Attribute1 = att1
Attribute2 = att2
End sub
Private mAttribute1 as string
Public Property Attribute1 as string
Get
return mAttribute1
End get
Set(ByVal value as string)
mAttribute1 = value
OnPropertyChanged("Attribute1")
End Set
End Property
Private mAttribute2 as string
Public Property Attribute2 as string
Get
return mAttribute2
End Get
Set(ByVal value as string)
mAttribute2 = value
OnPropertyChanged("Attribute2")
End Set
End Property
Public Sub OnPropertyChanged(ByVal name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
Public Sub ChangeDataFormat()
'change from one format to the other
End Sub
End Class
Data Generator Class:
Public Class dataGenerator()
private myThread as New System.Theading.Thread(address of StartDataGeneration)
Public Sub new()
mDataList = new bindingList(of Data)
mDataList.RaiseListChangedEvents = True
Private WithEvents mDataList as bindingList(Of Data)
Public readonly DataList as bindingList(of Data)
Get
Return mDataList
End Get
End property
Private Sub StartDataGeneration()
dim att1 as integer = 1
dim att2 as integer = 2
for i as Integer = 0 to 1000
mDataList.Insert(0,New Data(att1.ToString,att2.ToString)
att1 *= 2
att2 *=3
next
End Sub
Public Sub StartDataThread()
myThread.Start()
End Sub
Public Sub ChangeDataFormat()
for each d as data in mDataList
d.ChangeDataFormat()
next
End Sub
End Class
Form:
Public class Form1
Private myGenerators as new BindingList(of dataGenerator)
Private myDataGrids as new BindingList(of DataGridView)
Private Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Mybase.Load
dim NumberOfGenerators as integer = Convert.ToInt32(My.Settings.CraneCount)
for i as integer = 1 to NumberOfGenerators
Dim newGenerator As New DataGenerator()
Dim newTab as Ne tabPage(i.ToString)
Dim NewGrid as New DataGridView
newTab.Controls.Add(newGrid)
newGrid.DataSource = newGenerator.DataList
myGenerators.Add(newGrid)
next
End Sub
Private Sub ButtonStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonStart.Click
for each generator as dataGenerator in myGenerators
generator.StartDataThread()
next
End Sub
Private Sub ButtonChangeFormat_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonChangeFormat.Click
for each generator as dataGenerator in myGenerators
generator.ChangeDataFormat()
next
End Sub
End Class
I know that there is a lot of code but I wanted to be clear. So when I click the start button the new items start appearing, however, once they get to the bottom of the grid the scroll bar doesn't appear. If I click the Change Format button the data changes format and updates in the grid properly. I was under the impression that the ListChanged event would automatically work with a bindinglist and datagridview. I tried calling update and refresh on myDataGridView and setting datagridview.datasource to nothing and then back to DataList.
Am I missing something?

Validating a checkListBox?

I have two forms (1 and 2). I have been battling with some code that would prevent the user from selecting an item in the checkedListBox that was not added into ListBox2 from the previous form (form1).
The code I have is kind of weird because even if the item was added to listbox2 from form1, it continues to display the msgBox. I need the msgBox to display only to those items that were not added to listbox2, form1.
Here is what I have:
Public Class Form1
Dim ActSubject As Boolean
Public Function ActivateSubject() As String
Return ActSubject
End Function
Private Sub ListBox2_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox2.TextChanged
Dim x As New Items
x.AvailableItems = ListBox2.Items.ToString
For Each x In ListBox2.Items
If ListBox2.Items.Contains(x) Then
ActSubject = True
Else
ActSubject = False
End If
Next
End Sub
End Class
Public Class Form2
Dim HaveActSubject As Boolean = Form1.ActivateSubject
Private Sub CheckedListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles CheckedListBox1.SelectedValueChanged
If HaveActSubject = False Then
MsgBox("Sorry! Subject should be activated six month before registration.")
End If
Return
End Sub
End Class
Public Class Form1
Public Function ActivateSubject(itm as string) As String
Return ListBox2.Items.Contains(itm)
End Function
End Class
Public Class Form2
Dim HaveActSubject As Boolean = Form1.ActivateSubject
Private Sub CheckedListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles CheckedListBox1.SelectedValueChanged
If Form1.ActivateSubject(CheckedListBox1.selectedValue) = False Then
MsgBox("Sorry! Subject should be activated six month before registration.")
End If
Return
End Sub
End Class

inheritance in VB.net

Not real sure how to ask this question... Some of my terms may be incorrect but hopefully I'll be able to get the question across. If I have a class something like this
Public Class Agency
public property ID as integer=0
public property Name as string=string.empty
Public sub new()
end sub
end class
and then a factory class that returns a list
Public Class Agency_Controller
Public Sub New()
end sub
Public function Fetch() as list(of Agency)
pop the list and return it
end function
end class
If I create another class say Agency_Misc and want to inherit the Agency Class I get, how to do that?
Public Class Agency_Misc
inherits Agency
public property Address as string=string.empty
end class
Now if I want to use the Agency_Misc, how do I get the Agency_Controller Fetch function? In the code if I were going after the agency... I do something like
Dim oS as list(of Agency)=nothing
dim oC as new Agency_Controller
os=oc.Fetch()
but if I want my list to have the list(of Agency_Misc) (because I was doing some more stuff)
how do I do that. I can't change list(of Agency) to list(of Agency_Misc) because it will tell me it can't convert it I think it was.
Anyway... I'd like to learn what it is I'm missing or what other approach I need to look into.
If you have defined your classes properly, you can do the following:
Define a BaseClass.
Define a DerivedClass which inherits from BaseClass
Define a List(Of BaseClass) and populate it with objects of DerivedClass (the List will accept objects of Dervived class, because these are, through inheritance, also objects of BaseClass.
Access the items in the list with a variable of Type DerivedClass.
What you CAN'T do is populate the list with objects of type BaseClass, and then attempt to access them using a variable of Type DerivedClass.
Ex. #1 THIS will work:
Public Class Form1
Private MyListOfBaseCLass As List(Of MyBaseClass)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyListOfBaseCLass = New List(Of MyBaseClass)
Dim dc As New MyDerivedCLass("City of Portland", "555 SW 5th Avenue")
MyListOfBaseCLass.Add(dc)
dc = New MyDerivedCLass("City of Salem", "222 E River Road")
MyListOfBaseCLass.Add(dc)
dc = New MyDerivedCLass("City of Denver", "333 SomeStreet")
MyListOfBaseCLass.Add(dc)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each dc As MyDerivedCLass In MyListOfBaseCLass
MsgBox(dc.MyName & ", " & dc.MyAddress)
Next
End Sub
End Class
THIS will FAIL:
Public Class Form1
Private MyListOfBaseCLass As List(Of MyBaseClass)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyListOfBaseCLass = New List(Of MyBaseClass)
Dim dc As New MyBaseClass("City of Portland")
MyListOfBaseCLass.Add(dc)
dc = New MyBaseClass("City of Salem")
MyListOfBaseCLass.Add(dc)
dc = New MyBaseClass("City of Denver")
MyListOfBaseCLass.Add(dc)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each dc As MyDerivedCLass In MyListOfBaseCLass
MsgBox(dc.MyName & ", " & dc.MyAddress)
Next
End Sub
End Class
You best set the properties in the constructor
Public Class Agency
Private m_ID As Integer
Public Property ID() As Integer
Get
Return m_ID
End Get
Set(ByVal value As Integer)
m_ID = value
End Set
End Property
Private m_name As String
Public Property Name() As String
Get
Return m_name
End Get
Set(ByVal value As String)
m_name = value
End Set
End Property
Sub New(ByVal id As Integer, ByVal name As String)
Me.m_ID = id
Me.m_name = name
End Sub
End Class
...
Dim HiDollar as New Agency(100, "High Dollar")

List Boxes in VB.NET

I want to manually add two items as "Active" and "Inactive" in a ListBox. When the user selects "Active", i want to get the value "A" and when "Inactive" is selected, i want to get "I".
How do i do this in VB.NET.
Are you using .NET 4? If so, the simplest solution is probably to use Tuple(Of String, String). Create a tuple of ("Active", "A") and another of ("Inactive", "I") and add those to the listbox. Then set the listbox's DisplayMember property to "Item1" and ValueMember to "Item2".
Or you could do the same sort of thing with an anonymous type.
The ListboxItemCollection is of type Object. You can create a custom ListItem like this
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
BindListBox()
End Sub
Private Sub BindListBox()
With ListBox1
.Items.Add(New CustomListItem("Acitve", "A"))
.Items.Add(New CustomListItem("Inactive", "I"))
.DisplayMember = "Text"
End With
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
MsgBox(CType(ListBox1.SelectedItem, CustomListItem).Value)
End Sub
End Class
''Custom ListItem Class
Public Class CustomListItem
Dim _text As String
Dim _value As String
Sub New(ByVal text As String, ByVal value As String)
Me._text = text
Me._value = value
End Sub
Public ReadOnly Property Text() As String
Get
Return _text
End Get
End Property
Public ReadOnly Property Value() As String
Get
Return _value
End Get
End Property
End Class
A simple option
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Debug.Print(ListBox1.Items(ListBox1.SelectedIndex).ToString.Substring(0, 1))
End Sub