How to assign class property as display data member in datagridview - vb.net

I am trying to display my data in datagridview. I created a class with different property and used its list as the datasource. it worked fine. but I got confused how to do that in case we have nested class.
My Classes are as follows:
class Category
property UIN as integer
property Name as string
end class
class item
property uin as integer
property name as string
property mycategory as category
end class
my data list as follows:
dim myDataList as list(of Item) = new List(of Item)
myDataList.Add(new Item(1,"item1",new category(1,"cat1")))
myDataList.Add(new Item(2,"item2",new category(1,"cat1")))
myDataList.Add(new Item(3,"item3",new category(1,"cat1")))
myDataList.Add(new Item(4,"item4",new category(2,"cat2")))
myDataList.Add(new Item(5,"item5",new category(2,"cat2")))
myDataList.Add(new Item(6,"item6",new category(2,"cat2")))
Now I binded the datagridview control like:
DGVMain.AutoGenerateColumns = False
DGVMain.ColumnCount = 3
DGVMain.Columns(0).DataPropertyName = "UIN"
DGVMain.Columns(0).HeaderText = "ID"
DGVMain.Columns(1).DataPropertyName = "Name"
DGVMain.Columns(1).HeaderText = "Name"
DGVMain.Columns(2).DataPropertyName = "" **'here i want my category name**
DGVMain.Columns(2).HeaderText = "category"
DGVMain.datasource = myDataList
DGVMain.refresh()
I have tried using mycategory.name but it didn't worked. What can be done to get expected result? Is there any better idea other than this to accomplish the same task?
Edited My question as per comment:
I have checked the link given by u. It was nice n very usefull. Since the code was in c# i tried to convert it in vb. Everything went good but failed at a point of case sensitive and next one is that i had my nested class name itemcategory and my property name was category. there it arouse the problem. it didn't searched for category but it searched for itemcategory. so confused on it. My Code as follows:
Private Sub DGVMain_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles DGVMain.CellFormatting
Dim DGVMain As DataGridView = CType(sender, DataGridView)
e.Value = EvaluateValue(DGVMain.Rows(e.RowIndex).DataBoundItem, DGVMain.Columns(e.ColumnIndex).DataPropertyName)
End Sub
Private Function EvaluateValue(ByRef myObj As Object, ByRef myProp As String) As String
Dim Ret As String = ""
Dim Props As System.Reflection.PropertyInfo()
Dim PropA As System.Reflection.PropertyInfo
Dim ObjA As Object
If myProp.Contains(".") Then
myProp = myProp.Substring(0, myProp.IndexOf("."))
Props = myObj.GetType().GetProperties()
For Each PropA In Props
ObjA = PropA.GetValue(myObj, New Object() {})
If ObjA.GetType().Name = myProp Then
Ret = EvaluateValue(ObjA, myProp.Substring(myProp.IndexOf(".") + 1))
Exit For
End If
Next
Else
PropA = myObj.GetType().GetProperty(myProp)
Ret = PropA.GetValue(myObj, New Object() {}).ToString()
End If
Return Ret
End Function

I'd just add a property to item called CategoryName that returns Category.Name and use that.
The Category is part of the Item, but that doesn't mean that you always have to give access to the whole Category to outside classes, just give access to the bits that they need access to at that time as to maximize encapsulation and minimize interdependencies.
Edit: In response to your comment
If you don't want to create the properties as mentioned in my answer above I don't think there is any real solution but you can use the 'CellFormatting' event to sort of get it to work where you set the DataPropertyName to a special identifier and then in the CellFormatting event handler you look up the real value to display. You can find an example of that here, look for tkrasinger's post (or AlexHinton's if you want to use reflection).

Public Class Category
Dim uni As Integer
Dim name As String
Public Sub New(ByVal i As Integer, ByVal n As String)
Me.UIN = i
Me.name = n
End Sub
Public Sub New()
End Sub
Property UIN() As Integer
Get
Return uni
End Get
Set(ByVal value As Integer)
uni = value
End Set
End Property
Property Names() As String
Get
Return Me.name
End Get
Set(ByVal value As String)
Me.name = value
End Set
End Property
**Public Overrides Function ToString() As String
Return name.ToString()
End Function**
End Class
Public Class item
Dim uni As Integer
Dim name As String
Dim category As New Category()
Property UIN() As Integer
Get
Return uni
End Get
Set(ByVal value As Integer)
uni = value
End Set
End Property
Property Names() As String
Get
Return Me.name
End Get
Set(ByVal value As String)
Me.name = value
End Set
End Property
Property mycategory() As Category
Get
Return Me.category
End Get
Set(ByVal value As Category)
Me.category = value
End Set
End Property
Public Sub New(ByVal i As Integer, ByVal nm As String, ByVal ct As Category)
Me.UIN = i
Me.Names = nm
Me.mycategory = ct
End Sub
End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim myDataList As List(Of item) = New List(Of item)
myDataList.Add(New item(1, "item1", New Category(1, "cat1")))
myDataList.Add(New item(2, "item2", New Category(1, "cat1")))
myDataList.Add(New item(3, "item3", New Category(1, "cat1")))
myDataList.Add(New item(4, "item4", New Category(2, "cat2")))
myDataList.Add(New item(5, "item5", New Category(2, "cat2")))
myDataList.Add(New item(6, "item6", New Category(2, "cat2")))
DGVMain.AutoGenerateColumns = False
DGVMain.ColumnCount = 3
DGVMain.Columns(0).DataPropertyName = "UIN"
DGVMain.Columns(0).HeaderText = "ID"
DGVMain.Columns(1).DataPropertyName = "Names"
DGVMain.Columns(1).HeaderText = "Name"
**DGVMain.Columns(2).DataPropertyName = "mycategory"**
DGVMain.Columns(2).HeaderText = "Category"
DGVMain.datasource = myDataList
DGVMain.refresh()
End Sub

Related

lists on custom listview are all the same, should be different in Visual Basic

How to display a list on a custom listview that varies like this :
true
Not like this:
false
where to see each other, everything is the same?
I created Daftar.vb using User Controls (Windows Forms) and I created a custom list view using FlowLayoutPanel and in it I entered the Daftar Toolbox
code :
Daftar.vb
Imports System.ComponentModel
Public Class Daftar1
#Region "Properties"
Private _title As String
Private _message As String
Private _icon As Image
<Category("Custom Props")>
Public Property Title As String
Get
Return _title
End Get
Set(ByVal value As String)
_title = value
judul.Text = value
End Set
End Property
<Category("Custom Props")>
Public Property Message As String
Get
Return _message
End Get
Set(ByVal value As String)
_message = value
deskripsi.Text = value
End Set
End Property
<Category("Custom Props")>
Public Property Icon As Image
Get
Return _icon
End Get
Set(ByVal value As Image)
_icon = value
gambar.Image = value
End Set
End Property
#End Region
End Class
RestaurantApp.vb
Public Class RestaurantApp
Private Sub PopulateItems()
Dim listItems As Daftar1() = New Daftar1(20) {}
Dim i As Integer
For i = 0 To listItems.Length - 1
listItems(i) = New Daftar1()
listItems(i).Title = "vdsvhd"
listItems(i).Message = "Penjelasan"
If i <> 0 Then
panelDaftar.Controls.Add(listItems(i))
End If
Next
End Sub
Private Sub RestaurantApp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call Me.PopulateItems()
End Sub
End Class
After I search on Stackoverflow and Youtube, I've managed to find the answer. The following is the code for RestaurantApp.vb :
Public Class RestaurantApp
Private Sub PopulateItems()
Dim listItems As Daftar1() = New Daftar1(5) {}
Dim judul As String() = New String(4) {"Burger", "Sosis", "Nasi", "Pizza", "Ayam"}
Dim penjelasan As String() = New String(4) {"a", "b", "c", "d", "e"}
Dim i As Integer
For i = 0 To listItems.Length - 1
If i < judul.Length And i < penjelasan.Length Then
listItems(i) = New Daftar1()
listItems(i).Title = judul(i)
listItems(i).Message = penjelasan(i)
If i <> 0 Then
panelDaftar.Controls.Add(listItems(i))
End If
End If
Next
End Sub
Private Sub RestaurantApp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call Me.PopulateItems()
End Sub
End Class
Thank you #anu6is and Stackoverflow

How can store a datagridview as a array in a cell of a mysql table

I want to store the content of a DataGridView in a array
and the other way round I want to read a array into a Datagridview.
I found this class on the net
Public Class Loads
Private L_nr As String
Private L_plz As String
Private L_km As String
Public Sub New(ByVal nr, ByVal plz, ByVal km)
L_nr = nr
L_plz = plz
L_km = km
End Sub
Public Property nr() As String
Get
Return L_nr
End Get
Set(ByVal Value As String)
L_nr = Value
End Set
End Property
Public Property plz() As String
Get
Return L_plz
End Get
Set(ByVal Value As String)
L_plz = Value
End Set
End Property
Public Property km() As String
Get
Return L_km
End Get
Set(ByVal Value As String)
L_km = Value
End Set
End Property
End Class
I xan use it like this
Private Sub DataGridViewLoads1_Click(sender As Object, e As EventArgs) Handles DataGridViewLoads1.Click
Dim al As New Collections.ArrayList()
al.Add(New Loads(123, 234, 1971))
DataGridViewLoads1.DataSource = al
End Sub
But its not what I want
You can use collection of class instances for displaying and editing data in DataGridView
Public Class Person
Public Property Id As Integer
Public Property Name As String
End Class
Create collection and show it in DataGridView
Dim persons = new List(Of Person) From
{
New Person { .Id = 1, .Name = "One" },
New Person { .Id = 2, .Name = "Two" },
New Person { .Id = 3, .Name = "Three" }
}
yourDataGridView.DataSource = persons
When you want save all data from DataGridView use same instance of persons or cast it from .DataSource
Dim dataToSave = DirectCast(yourDataGridView.DataSource, List(Of Person))
Then serialize data to string in json format for example(feel free to use any other format)
Dim serializedData AS String = Newtonsoft.Json.JsonConvert.SerializeObject(dataToSave)
Then save that string in database.
For displaying data from database:
// retrieve value from database
Dim serializedData As String = GetFromDatabaseYourFunction()
Dim data = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of Person))(serializedData)
yourDataGridView.DataSource = data

Extracting property values from a dictionary

I am attempting to write a subroutine that will deserialize a dictionary from a .ser file (this bit works fine) and then repopulate several lists from this dictionary (this is the bit I cannot do).
The dictionary contains objects (I think) of a custom class I wrote called "Photo Job" which has properties such as ETA, notes, medium etc. (Declared as such)
Dim photoJobs As New Dictionary(Of String, PhotoJob)
In short, I want to be able to extract every entry of each specific property into an separate arrays (one for each property) and I can go from there.
Any help would be appreciated, I may be going about this completely the wrong way, I'm new to VB. The relevant code is below:
Photo Job Class:
<Serializable()> _Public Class PhotoJob
Private intStage As Integer 'Declare all local private variables
Private ID As String
Private timeLeft As Integer
Private material As String '
Private note As String
Private path As String
Private finished As Boolean = False
'Declare and define properties and methods of the class
Public Property productionStage() As Integer
Get
Return intStage
End Get
Set(ByVal Value As Integer)
intStage = Value
End Set
End Property
Public Property photoID() As String
Get
Return ID
End Get
Set(ByVal Value As String)
ID = Value
End Set
End Property
Public Property ETA() As Integer
Get
Return timeLeft
End Get
Set(ByVal Value As Integer)
timeLeft = Value
End Set
End Property
Public Property medium() As String
Get
Return material
End Get
Set(ByVal Value As String)
material = Value
End Set
End Property
Public Property notes() As String
Get
Return note
End Get
Set(ByVal Value As String)
note = Value
End Set
End Property
Public Property imagePath() As String
Get
Return path
End Get
Set(ByVal Value As String)
path = Value
End Set
End Property
Public Property complete() As Boolean
Get
Return finished
End Get
Set(value As Boolean)
finished = value
End Set
End Property
Public Sub nextStage()
If intStage < 4 Then
intStage += 1
ElseIf intStage = 4 Then
intStage += 1
finished = True
End If
End Sub
End Class
Subroutines involved in de/serialisation:
Private Sub BackupAllToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles BackupAllToolStripMenuItem.Click
Dim formatter As New BinaryFormatter
Dim backupFile As New FileStream(Strings.Replace(Strings.Replace(Now, ":", "_"), "/", ".") & ".ser", FileMode.Create, FileAccess.Write, FileShare.None)
formatter.Serialize(backupFile, photoJobs)
backupFile.Close()
MsgBox("Collection saved to file")
End Sub
Private Sub RestoreFromFileToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RestoreFromFileToolStripMenuItem.Click
With OpenFileDialog 'Executes the following sets/gets/methods of the OpenFileDialog
.FileName = ""
.Title = "Open Image File"
.InitialDirectory = "c:\"
.Filter = "Serial Files(*.ser)|*ser"
.ShowDialog()
End With
Dim backupPathStr As String = OpenFileDialog.FileName
Dim deSerializer As New BinaryFormatter
Dim backupFile As New FileStream(backupPathStr, FileMode.Open)
photoJobs = deSerializer.Deserialize(backupFile)
backupFile.Close()
End Sub
From what I can see using the autos menu, the saving/restoring of the dictionary works just fine.
First, if you are using VS2010+, you can greatly reduce boilerplate code using autoimplemented properties:
<Serializable()>
Public Class PhotoJob
Public Property productionStage() As Integer
Public Property photoID() As String
Public Property ETA() As Integer
etc
End Class
That is all that is needed, all the boilerplate code is handled for you. Second, with this line:
photoJobs = deSerializer.Deserialize(backupFile)
Your deserialized photojobs will be a generic Object, not a Dictionary. You should turn on Option Strict so VS will enforce these kinds of errors. This is how to deserialize to Type:
Using fs As New FileStream(myFileName, FileMode.Open)
Dim bf As New BinaryFormatter
PhotoJobs= CType(bf.Deserialize(fs), Dictionary(Of String, PhotoJob))
End Using
Using closes and disposes of the stream, CType converts the Object returned by BF to an actual dictionary
To work with the Dictionary (this has nothing to do with Serialization) you need to iterate the collection to get at the data:
For Each kvp As KeyValuePair(Of String, PhotoJob) In PhotoJobs
listbox1.items.Add(kvp.value.productionStage)
listbox2.items.Add(kvp.value.ETA)
etc
Next
The collection is a made of (String, PhotoJob) pairs as in your declaration, and when you add them to the collection. They comeback the same way. kvp.Key will be the string key used to identify this job in the Dictionary, kvp.Value will be a reference to a PhotoJobs object.
As long as VS/VB knows it is a Dictionary(of String, PhotoJob), kvp.Value will act like an instance of PhotoJob (which it is).

sort results (find method) not working

I am using ArcGIS. I am trying to sort the data manually after its found. I created a property class and loop through a Tlist to scrub unwanted data. However right before it binds to the data grid, I receive a cast error. I assume something is coming back null. Am I missing something??
Public Class temp
Public Sub New()
End Sub
Public Property DisplayFieldName As String
Public Property Feature As ESRI.ArcGIS.Client.Graphic
Public Property FoundFieldName As String
Public Property LayerId As Integer
Public Property LayerName As String
Public Property Value As Object
End Class
Public Class templst
Public Sub New()
Dim findresult = New List(Of temp)
End Sub
Private _findresult = findresult
Public Property findresult() As List(Of temp)
Get
Return _findresult
End Get
Set(ByVal value As List(Of temp))
_findresult = value
End Set
End Property
End Class
Private Sub FindTask_Complete(ByVal sender As Object, ByVal args As FindEventArgs)
Dim newargs As New templst() 'puts Tlist (temp) into property
Dim templistNUMONLY As New List(Of temp) 'Tlist of temp
For Each r In args.FindResults 'class in compiled dll.
If Regex.Match(r.Value.ToString, "[0-9]").Success Then
templistNUMONLY.Add(New temp() With {.LayerId = r.LayerId,
.LayerName = r.LayerName,
.Value = r.Value,
.FoundFieldName = r.FoundFieldName,
.DisplayFieldName = r.DisplayFieldName,
.Feature = r.Feature})
End If
Next
newargs.findresult = templistNUMONLY
Dim sortableView As New PagedCollectionView(newargs.findresult)
FindDetailsDataGrid.ItemsSource = sortableView 'populate lists here
End Sub
BIND TO GRID HERE: (Error here)
Private Sub FindDetails_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
' Highlight the graphic feature associated with the selected row
Dim dataGrid As DataGrid = TryCast(sender, DataGrid)
Dim selectedIndex As Integer = dataGrid.SelectedIndex
If selectedIndex > -1 Then
'''''''''''''''''CAST ERROR HERE:
Dim findResult As FindResult = CType(FindDetailsDataGrid.SelectedItem, FindResult)
You populate FindDetailsDataGrid with objects of type temp, but you try to cast it to type FindResult instead. You should do:
Dim selectedTemp As temp = CType(FindDetailsDataGrid.SelectedItem, temp)
'*Create find result from selected temp object here*

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")