VB.NET XML Serialize a List of Inherited Objects - vb.net

I'm trying to serialize a list of inherited objects. I can serialize each object individually when its declared according to its true type, but when its a list of the base type the serializer gets confused because its expecting to serialize a "base" object but then see different objects that had inherited the "base" object.
Any ideas on how to easily solve this? I've done a bunch of reading and have not found an elegant easy to maintain way to do this.
Trying to serialize:
'Define a list of the common inherited base for all print elements.
' This allows all types of print elements to be added to one list and in the user defined order
' Order is important for the layer of objects when 'drawing' them on the canvas during the on print options
<XmlArrayAttribute("ElementsList")> 'Tell the XML Seralizer this is a list
Public Elements As New List(Of CardItemBase) 'XML Serializer does not like this becuase the elements in this list are not CardItemBase, they are that + stuff, and it does not know what to do with stuff
Here are two examples of items that inherited the base, both of which will serialize (even in a list) if declared as their true type.:
Public Class TextString
'Inherit the common properties for a card item
Inherits CardItemBase
'Vars to hold string info to use when printing
Public StringToPrint As String = String.Empty
Public XLocation As Single = 0
Public YLocation As Single = 0
'Font info (store values instead of a Pen since Pen requires dispose and also does not work with Xml Serializing)
Public Font As String = Nothing
Public FontSize As Integer = 0
Public FontColor As System.Drawing.KnownColor = Drawing.KnownColor.Black 'Note, does NOT require dispose
'Constructor to force users to pass in all info
Public Sub New() 'Create an empty Sub New Overload for use with XML Serializer
End Sub
Public Sub New(ByVal CardSide As CardSideOptions, ByVal InputStringToPrint As String, ByVal TextFont As String, ByVal TextSize As Integer, ByVal TextColor As System.Drawing.KnownColor, ByVal InputXLocation As Single, ByVal InputYLocation As Single)
'Set the inherited objects
MyBase.New(CardSide:=CardSide)
'Save passed in info
StringToPrint = InputStringToPrint
Font = TextFont
FontSize = TextSize
FontColor = TextColor
XLocation = InputXLocation
YLocation = InputYLocation
End Sub
''' <summary>
''' Return the ture type of this object as DriverJob.PrintElementTypes even if the item is nested in a CardItemBase list.
''' </summary>
<XmlIgnore()>
Public Overrides ReadOnly Property MyType() As PrintElementTypes
Get
Return PrintElementTypes.Text
End Get
End Property
<XmlIgnore()>
Public Overrides ReadOnly Property ToString() As String
Get
Try
'Create a string that descipes this object
Dim ReturnStr As String = ""
'Concatinate a description of each element
ReturnStr += "X: " & XLocation.ToString() & ", Y: " & YLocation.ToString() & ", "
ReturnStr += Font & ", " & FontSize & ", "
ReturnStr += FontColor.ToString() & ", "
ReturnStr += "'" & StringToPrint & "'"
'Return the completed string.
Return ReturnStr
Catch ex As Exception
'Just return the error string
Return ex.Message
End Try
End Get
End Property
End Class
''' <summary>
''' Sub class for passing images to print to the printing method.
''' </summary>
Public Class Image
'Inherit the common properties for a card item
Inherits CardItemBase
'Vars to hold image info to use when printing
Public ImageFilePathToUse As String = ""
Public XLocation As Single = 0
Public YLocation As Single = 0
Public Height As Single = 0
Public Width As Single = 0
'Constructor to force users to pass in all info
Public Sub New() 'Create an empty Sub New Overload for use with XML Serializer
End Sub
Public Sub New(ByVal CardSide As CardSideOptions, ByVal InputImageFilePathToUse As String, Optional ByVal InputXLocation As Single = 0, Optional ByVal InputYLocation As Single = 0, Optional ByVal InputHeight As Single = 0, Optional ByVal InputWidth As Single = 0)
'Set the inherited objects
MyBase.New(CardSide:=CardSide)
'Save passed in info
ImageFilePathToUse = InputImageFilePathToUse
XLocation = InputXLocation
YLocation = InputYLocation
Height = InputHeight
Width = InputWidth
End Sub
''' <summary>
''' Return the ture type of this object as DriverJob.PrintElementTypes even if the item is nested in a CardItemBase list.
''' </summary>
<XmlIgnore()>
Public Overrides ReadOnly Property MyType() As PrintElementTypes
Get
Return PrintElementTypes.Image
End Get
End Property
''' <summary>
''' Creates a simple string description of the object
''' </summary>
<XmlIgnore()>
Public Overrides ReadOnly Property ToString() As String
Get
Try
'Create a string that descipes this object
Dim ReturnStr As String = ""
'Concatinate a description of each element
ReturnStr += "X: " & XLocation.ToString() & ", Y: " & YLocation.ToString() & ", "
ReturnStr += "Height: " & Height.ToString() & ", Width: " & Width.ToString() & ", "
ReturnStr += ImageFilePathToUse
'Return the completed string.
Return ReturnStr
Catch ex As Exception
'Just return the error string
Return ex.Message
End Try
End Get
End Property
End Class

After a few more hours of reading and testing I found a solution that will work for me.
Above the base class definition the XML include tag can be used define all the types that inherited this base class so the serializer won't be confused. This adds only one step to do when adding classes that inherit this base class, for my use I can live with this.
Here is line of code I added:
'Class to hold common properties that may be needed for describing all card elements. This is intented to be inherited
<XmlInclude(GetType(TextString)), XmlInclude(GetType(Line)), XmlInclude(GetType(Rectangle)), XmlInclude(GetType(Image)), XmlInclude(GetType(PrintAndTopcoatBlocking)), XmlInclude(GetType(MagstripeSetup)), XmlInclude(GetType(SmartCardSetup))>
Public MustInherit Class CardItemBase

Related

VB.NET Search ListBox for string and return specific data

I have a populated listbox. Each item has a string of data with id's and values. How would i search for the id and receive the vale?
If i search for 'itemColor' i would like it to return each boot color in a new msgbox.
itemName="boots" itemCost="$39" itemColor="red"
itemName="boots" itemCost="$39" itemColor="green"
itemName="boots" itemCost="$39" itemColor="blue"
itemName="boots" itemCost="$39" itemColor="yellow"
I understand there are different and easier ways to do this but i need to do it this way.
Thanks!
Here's one way to do it involving parsing the text as XML:
' Here's Some Sample Text
Dim listboxText As String = "itemName=""boots"" itemCost=""$39"" itemColor=""red"""
' Load XML and Convert to an Object
Dim xmlDocument As New System.Xml.XmlDocument
xmlDocument.LoadXml("<item " & listboxText & "></item>")
Dim item = New With {.ItemName = xmlDocument.DocumentElement.Attributes("itemName").Value,
.ItemCost = xmlDocument.DocumentElement.Attributes("itemCost").Value,
.ItemColor = xmlDocument.DocumentElement.Attributes("itemColor").Value}
' Write It Out as a Test
Console.WriteLine(item.ItemName & " " & item.ItemCost & item.ItemColor)
Console.Read()
Create a class (or structure), the appropriate properties, a default constructor, a parametized constructor and an Override of .ToString.
Public Class Item
Public Property Name As String
Public Property Cost As String
Public Property Color As String
Public Sub New()
End Sub
Public Sub New(sName As String, sCost As String, sColor As String)
Name = sName
Cost = sCost
Color = sColor
End Sub
Public Overrides Function ToString() As String
Return $"{Name} - {Cost} - {Color}"
End Function
End Class
Item objects are added to the list box calling the parameterized constructor. The list box calls .ToString on the objects to determine what to display.
Private Sub FillList()
ListBox3.Items.Add(New Item("boots", "$39", "red"))
ListBox3.Items.Add(New Item("boots", "$39", "green"))
ListBox3.Items.Add(New Item("boots", "$39", "blue"))
ListBox3.Items.Add(New Item("boots", "$39", "yellow"))
End Sub
Since we added Item objects to the list box, we can cast each list item back to the Item type and access its properties.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sb As New StringBuilder
For Each i In ListBox3.Items
sb.AppendLine(DirectCast(i, Item).Color)
Next
MessageBox.Show(sb.ToString)
End Sub

How can I print from an object?

I am having a problem getting my program to print an array. I have created a class with code and I want to be able to use the class to print the array. I have submitted my code below. hopefully Y'all can help me out thanks.
Option Strict On
Imports System.IO
Imports FinalLIB
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim fsrFile As StreamReader = New StreamReader("Cars.csv")
Dim line, splitLine(1) As String
Dim bestCars(14) As Cars
Dim counter As Integer
Do Until fsrFile.EndOfStream
line = fsrFile.ReadLine
splitLine = Split(line, ",")
bestCars(counter) = New Cars(splitLine(0), (splitLine(1)), (splitLine(2)), (splitLine(3)))
counter += 1
Loop
Dim strCarMake, strCarModel, intyear, strColorc As Cars
Console.WriteLine(bestCars(3))
End Sub
This is the code from my library created.
Option Strict On
Public Class Cars
Private strCarMake As String
Private strCarModel As String
Private intYear As String
Private strColor As String
Public Sub New(ByVal bvstrCarMake As String, ByVal bvstrCarModel As String, ByVal bvintYear As String, ByVal bvstrColor As String)
prpCarMake = bvstrCarMake
prpYear = CInt(bvintYear)
prpCarModel = bvstrCarModel
prpColor = bvstrColor
End Sub
Public Property prpCarMake() As String
Get
Return strCarMake
End Get
Set(bvstrCarMake As String)
strCarMake = bvstrCarMake
End Set
End Property
Public Property prpCarModel() As String
Get
Return strCarModel
End Get
Set(bvstrCarModel As String)
strCarModel = bvstrCarModel
End Set
End Property
Public Property prpYear() As Integer
Get
Return CInt(intYear)
End Get
Set(bvintYear As Integer)
intYear = CType(bvintYear, String)
End Set
End Property
Public Property prpColor() As String
Get
Return strColor
End Get
Set(bvstrColor As String)
strColor = bvstrColor
End Set
End Property
Public ReadOnly Property prpIsOld() As Boolean
Get
If prpYear > 2010 Then
Return True
Else
Return False
End If
End Get
End Property
'Public ReadOnly Property prpSSN() As String
'Get
'Return strSSN
'End Get
'End Property
Public Function ReturnFullInfo() As String
Return "Make: " & prpCarMake & " Model: " & prpCarModel & "Year: " & prpYear & "Color: " & prpColor
End Function
End Class

VB.NET - Cannot bind to the new display member

I'm trying to assign the DataSource for a ComboBox that will allow the user to select a member. I'm receiving this error when run my application:
Cannot bind to the new display member.
Parameter name: newDisplayMember.
Here's my code:
Private Sub StartScreen_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'GetAllELData()
ddlMember.DataSource = GetMemberList()
ddlMember.DisplayMember = "DisplayName"
ddlMember.ValueMember = "ID"
End Sub
Private Function GetMemberList() As List(Of Member)
Dim rval = New List(Of Member)
Dim dv As DataView = New DataView
Dim myConnString = ConfigurationSettings.AppSettings("ConnString")
Try
dv = SqlHelper.ExecuteDataset(myConnString, CommandType.StoredProcedure, "spGetData").Tables(0).DefaultView
Catch ex As Exception
MessageBox.Show(ex.Message, "Database Error", MessageBoxButtons.OK)
End Try
For Each row As DataRowView In dv
Dim mbrNum As String = row.Item("IMMBR_CD").ToString()
Dim mbrName As String = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(row.Item("IMMBR_NM20").ToLower())
Dim mbrState As String = row.Item("IMMBR_ST").ToString()
'assigns the member data to the list of members
rval.Add(New Member(mbrNum, mbrName, mbrState))
Next
Return rval
End Function
And then my class definition:
Public Class Member
Public ID As String
Public Name As String
Public State As String
Public DisplayName As String
Public Sub New(ByVal i As String, ByVal n As String, ByVal s As String)
ID = i
Name = n
State = s
DisplayName = ID & " - " & Name & ", " & State
End Sub
Public Overrides Function ToString() As String
Dim rval As String = ID & " - " & Name & ", " & State
Return rval
End Function
Public Function GetID() As String
Return ID
End Function
Public Function GetName() As String
Return Name
End Function
Public Function GetState() As String
Return State
End Function
End Class
I don't know why I'm getting the error. The application correctly loads the member as intended and works just fine once I click "Continue" on the error popup. Everything I've found about the error is for people passing a table as their DataSource instead of a custom class like me and the answers contain only code snippets rather than an explanation of the why there's a problem.
Can anyone help me figure out what's wrong here?
Thanks a bunch!
The errors were caused by binding directly to the fields. Defining those as properties and binding to the properties solved the issue.
Public ReadOnly Property GetID() As String
Get
Return Me.ID
End Get
End Property
Public ReadOnly Property GetName() As String
Get
Return Me.Name
End Get
End Property
Public ReadOnly Property GetState() As String
Get
Return Me.State
End Get
End Property
Public ReadOnly Property GetDisplayName() As String
Get
Return Me.DisplayName
End Get
End Property
And:
Private Sub StartScreen_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'GetAllELData()
ddlMember.DataSource = GetMemberList()
ddlMember.DisplayMember = "GetDisplayName"
ddlMember.ValueMember = "GetID"
End Sub

Adding items to ListView from a Class

I am having trouble adding an item to a listview from one of my classes. I am missing something that is obviously over my head. If someone could help me to understand what I am missing that would be great.
I don't know how much detail I need to provide. What I am trying to do is to basic so I know I have to be missing something. I have a class that I am trying to use to add an item to a listview I have on a form. There are no errors thrown, yet nothing gets added.
I have even tried using something as simple as frmGiveaways.lstAccounts.items.add("wtf") in the class, it doesn't throw any errors, the line is processed, yet no items appear in the list.
What are some things that would keep me from being able to do this?
Here is the class
Imports Simple_IRC_Client.Delegates
Imports System.Text.RegularExpressions
''' <summary>
''' Handles minimal IRC server response messages.
''' </summary>
Public Class OutputMessages : Implements IDisposable
#Region " Private Members "
Private ReadOnly ColorQuit As Color = Color.FromArgb(102, 54, 31)
Private ReadOnly ColorPrivmsg As Color = Color.FromArgb(76, 76, 76)
Private ReadOnly ColorTopic As Color = Color.FromArgb(176, 55, 176)
Private ReadOnly ColorKick As Color = Color.FromArgb(199, 50, 50)
Private ReadOnly ColorUserEvent As Color = Color.FromArgb(128, 128, 128)
Private WithEvents _ircConnection As InitiateConnection
Private _mainView As MainView
Private _window As RichTextBox
#End Region
#Region " Constructor "
Public Sub New(ByVal mainView As MainView, ByVal ircConnection As InitiateConnection)
_mainView = mainView
_ircConnection = ircConnection
_window = _mainView.rtbChannelView
End Sub
#End Region
#Region " EventArghs "
Private Sub ServerResponse(ByVal serverResponse As String) Handles _ircConnection.ServerResponseOutputEventArghs
' This setting has only been added for demonstration purposes of what raw data
' looks like.
If _mainView.mnuMainMenuOptionsrawData.Checked Then
OutputResponse(_window, serverResponse, Color.Black)
Exit Sub
End If
Dim parts() As String = serverResponse.Split(" "c)
Dim address As String = parts(0)
Select Case parts(1)
Case "PRIVMSG" : Privmsg(address, serverResponse.Substring(indexOf(serverResponse, 3) + 1).Substring(1))
Case "JOIN" : Join(address)
Case "PART", "QUIT" : Quit(address)
Case "ERROR" : Disconnected()
Case "332" : TopicOnjoin(serverResponse.Substring(indexOf(serverResponse, 4) + 1).Substring(1))
End Select
End Sub
#End Region
#Region " Private"
''' <summary>
''' Outputs a GUI message on me/user Privmsg.
''' </summary>
''' <param name="address">The source of the user's local host.</param>
''' <param name="message">The message text.</param>
''' <remarks>
''' Displays an output message to the normalview window with correct format and colouring on Me,
''' User Privmsg.
''' </remarks>
Private Sub Privmsg(ByVal address As String, ByVal message As String)
Dim outputFormat As String = String.Format("<{0}> {1}", Split(address), message)
OutputResponse(_window, outputFormat, Color.Black)
Select Case message
Case "" : _ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "{0}", Split(address)))
Case frmGiveaways.keyword
_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "recieved keyword", Split(address)))
frmGiveaways.lstAccountsEntered.Items.Add(Split(address))
End Select
End Sub
Private Sub Join(ByVal address As String)
If Split(address) = ConnectionInformation.ChannelNick Then
Exit Sub
End If
Dim outputFortmat As String = String.Format("{0} has joined the conversation.", Split(address))
OutputResponse(_window, outputFortmat, ColorUserEvent)
'Welcome message proof of concept
'_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "Welcome, {0}", Split(address)))
End Sub
''' <summary>
''' Outputs a GUI message on user Quitting.
''' </summary>
''' <param name="address">The source of the user's local host.</param>
''' <remarks>
''' Displays an output message to the normalview window with correct format on user Quitting with Quit message.
''' </remarks>
Private Sub Quit(ByVal address As String)
Dim outputFortmat As String = String.Format("{0} has left the conversation.", Split(address))
OutputResponse(_window, outputFortmat, ColorUserEvent)
End Sub
Private Sub Disconnected()
Dim outputFortmat As String = "Disconnected!"
OutputResponse(_window, outputFortmat, Color.Red)
End Sub
Private Sub TopicOnjoin(ByVal subject As String)
OutputResponse(_window, String.Format("The chat's topic is: {0} ", subject), Color.Black)
NewLine()
End Sub
#End Region
#Region " Output Response "
''' <summary>
''' Displays the servers output response message.
''' </summary>
''' <param name="control">The control name.</param>
''' <param name="output">The server output.</param>
''' <param name="color">The control output line color</param>
''' <remarks>
''' Responsible for displaying all server and user response messages.
''' </remarks>
Public Sub OutputResponse(ByVal control As RichTextBox, ByVal output As String, ByVal color As Color)
Dim outputFormat As String = String.Format("{0}", output)
If control.InvokeRequired Then
control.Invoke(New OutputEventHandler(AddressOf OutputResponse), control, output, color)
Else
Dim start = control.TextLength
Dim length = outputFormat.Length
With control
.AppendText(outputFormat & Environment.NewLine)
.ScrollToCaret()
.Select(start, length)
.SelectionColor = color
End With
End If
End Sub
Private Sub NewLine()
If _window.InvokeRequired Then
_window.Invoke(New MethodInvoker(AddressOf NewLine))
Else
_window.AppendText(Environment.NewLine)
End If
End Sub
#End Region
#Region " Functions "
''' <summary>
'''
''' </summary>
''' <param name="s"></param>
''' <param name="instance"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function indexOf(ByVal s As String, ByVal instance As Integer) As Integer
Dim startAt As Integer = -1
For x As Integer = 1 To instance
startAt = s.IndexOf(" "c, startAt + 1)
Next
Return startAt
End Function
Private Function Split(ByVal name As String) As String
Return name.Split("!"c)(0)
End Function
#End Region
#Region " IDisposable "
Public Sub dispose() Implements IDisposable.Dispose
End Sub
#End Region
End Class
The part I am having a problem with is PrivMsg under the Region Private.
you could create a method on the form which receives a string to create a new LV item from the text passed:
Public Sub AddNewLVItem(txtName As String)
Dim LVI as New ListViewItem
LVI.Text = txtName
LVI.Group = xxx ' whatever other props there are
lstaccounts.items.Add(LVI)
End Sub
or shorthand, if there are no subitems, groups etc
lstaccounts.items.Add(New ListViewItem(txtName))
EDIT:
TYPICALLY, the form name is blank on MDI child forms only, I am not sure why that is the case here, but it obviously is. Forms are classes and SHOULD be instanced for use. They can use the old default instance method (FormName.Show) but that exists mainly for compatibility back to the VB4/5/6 days when forms were something apart from classes. The old default instance also makes it easier for tinkerers (non programmers) who dont have a clue about OOP, to get something woking easily.
First, you will need a reference to frmGiveAways with app level scope so that other classes all reference the same object. Add a module to your project (if there is not already one) and add:
Friend frmGive As frmGiveAways
(Or change the form name to something like FormGiveAways so the instance name and all the code referencing it can still use frmGiveAways).
Now, when you go to show the form in the menu:
If frmGive Is Nothing Then ' check to see if it already exists
frmGive = New frmGiveAways
frmGive.Show ' could be a separate 'If' if needed
End if
Now there is one instance of frmGiveAways using the reference frmGive and as long as everyone uses that reference, things will work fine. In the 'Sub AddEntry' it would pay to set a break and monitor the Me.Name value for a while to make sure all the calling code is properly refactored.
HTH
Instead of hard coding the listview, try passing it into the sub as a parameter.
Something like this:
Private Sub Privmsg(ByVal address As String, ByVal message As String, ByRef LV as ListView)
Dim outputFormat As String = String.Format("<{0}> {1}", Split(address), message)
OutputResponse(_window, outputFormat, Color.Black)
Select Case message
Case "" : _ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "{0}", Split(address)))
Case frmGiveaways.keyword
_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "recieved keyword", Split(address)))
LV.Items.Add(Split(address))
End Select
End Sub
The basic syntax to add items to a ListView is this:
' Create list view items
Dim item1 As New ListViewItem("Item #1", 0)
Dim item2 As New ListViewItem("Item #2", 1)
Dim item3 As New ListViewItem("Item #3", 2)
Then you can add the list view items to the list view, either individually or as a group, like this:
Adding item one-by-one:
ListView1.Items.Add(item1)
ListView1.Items.Add(item2)
ListView1.Items.Add(item3)
Adding several items at once:
ListView1.Items.AddRange(New ListViewItem() {item1, item2, item3})
Note: The ListView1.Items.Add() and ListView1.Items.AddRange() methods both need ListViewItem objects, not string values.

how to add value to combobox item

How can I add data value of each item to combobox in Visual Basic 2010?
Like html drop-down box.
Or is there anyway to add values to each item ?
I am adding item from MySQL database like this:
Command = New MySqlCommand("SELECT * FROM `maillist` WHERE l_id = '" & id & "'", connection)
Command.CommandTimeout = 30
Reader = Command.ExecuteReader()
If Reader.HasRows = True Then
While Reader.Read()
ComboBox1.Items.Add(Reader("name"))
End While
End If
I need to add Reader("ID") as value of each item...
Although this question is 5 years old I have come across a nice solution.
Use the 'DictionaryEntry' object to pair keys and values.
Set the 'DisplayMember' and 'ValueMember' properties to:
Me.myComboBox.DisplayMember = "Key"
Me.myComboBox.ValueMember = "Value"
To add items to the ComboBox:
Me.myComboBox.Items.Add(New DictionaryEntry("Text to be displayed", 1))
To retreive items like this:
MsgBox(Me.myComboBox.SelectedItem.Key & " " & Me.myComboBox.SelectedItem.Value)
I am assuming that you are wanting to add items to a ComboBox on an Windows form. Although Klaus is on the right track I believe that the ListItem class is a member of the System.Web.UI.WebControls namespace. So you shouldn't be using it in a Windows forms solution. You can, however, create your own class that you can use in its place.
Create a simple class called MyListItem (or whatever name you choose) like this:
Public Class MyListItem
Private mText As String
Private mValue As String
Public Sub New(ByVal pText As String, ByVal pValue As String)
mText = pText
mValue = pValue
End Sub
Public ReadOnly Property Text() As String
Get
Return mText
End Get
End Property
Public ReadOnly Property Value() As String
Get
Return mValue
End Get
End Property
Public Overrides Function ToString() As String
Return mText
End Function
End Class
Now when you want to add the items to your ComboBox you can do it like this:
myComboBox.Items.Add(New MyListItem("Text to be displayed", "value of the item"))
Now when you want to retrieve the value of the selected item from your ComboBox you can do it like this:
Dim oItem As MyListItem = CType(myComboBox.SelectedItem, MyListItem)
MessageBox.Show("The Value of the Item selected is: " & oItem.Value)
One of the keys here is overriding the ToString method in the class. This is where the ComboBox gets the text that is displayed.
Matt made an excellent point, in his comment below, about using Generics to make this even more flexible. So I wondered what that would look like.
Here's the new and improved GenericListItem class:
Public Class GenericListItem(Of T)
Private mText As String
Private mValue As T
Public Sub New(ByVal pText As String, ByVal pValue As T)
mText = pText
mValue = pValue
End Sub
Public ReadOnly Property Text() As String
Get
Return mText
End Get
End Property
Public ReadOnly Property Value() As T
Get
Return mValue
End Get
End Property
Public Overrides Function ToString() As String
Return mText
End Function
End Class
And here is how you would now add Generic items to your ComboBox. In this case an Integer:
Me.myComboBox.Items.Add(New GenericListItem(Of Integer)("Text to be displayed", 1))
And now the retrieval of the item:
Dim oItem As GenericListItem(Of Integer) = CType(Me.myComboBox.SelectedItem, GenericListItem(Of Integer))
MessageBox.Show("The value of the Item selected is: " & oItem.Value.ToString())
Keep in mind that the type Integer can be any type of object or value type. If you want it to be an object from one of your own custom classes that's fine. Basically anything goes with this approach.
If you want to use SelectedValue then your combobox must be databound.
To set up the combobox:
ComboBox1.DataSource = GetMailItems()
ComboBox1.DisplayMember = "Name"
ComboBox1.ValueMember = "ID"
To get the data:
Function GetMailItems() As List(Of MailItem)
Dim mailItems = New List(Of MailItem)
Command = New MySqlCommand("SELECT * FROM `maillist` WHERE l_id = '" & id & "'", connection)
Command.CommandTimeout = 30
Reader = Command.ExecuteReader()
If Reader.HasRows = True Then
While Reader.Read()
mailItems.Add(New MailItem(Reader("ID"), Reader("name")))
End While
End If
Return mailItems
End Function
Public Class MailItem
Public Sub New(ByVal id As Integer, ByVal name As String)
mID = id
mName = name
End Sub
Private mID As Integer
Public Property ID() As Integer
Get
Return mID
End Get
Set(ByVal value As Integer)
mID = value
End Set
End Property
Private mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
End Class
Instead of adding Reader("Name") you add a new ListItem. ListItem has a Text and a Value property that you can set.
Yeah, for most cases, you don't need to create a class with getters and setters. Just create a new Dictionary and bind it to the data source. Here's an example in VB using a for loop to set the DisplayMember and ValueMember of a combo box from a list:
Dim comboSource As New Dictionary(Of String, String)()
cboMenu.Items.Clear()
For I = 0 To SomeList.GetUpperBound(0)
comboSource.Add(SomeList(I).Prop1, SomeList(I).Prop2)
Next I
cboMenu.DataSource = New BindingSource(comboSource, Nothing)
cboMenu.DisplayMember = "Value"
cboMenu.ValueMember = "Key"
Then you can set up a data grid view's rows according to the value or whatever you need by calling a method on click:
Private Sub cboMenu_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboMenu.SelectionChangeCommitted
SetListGrid(cboManufMenu.SelectedValue)
End Sub
Now you can use insert method instead add
' Visual Basic
CheckedListBox1.Items.Insert(0, "Copenhagen")