Get value of a property with propertyinfo object - vb.net

Is there a way to get value of a object properties with a propertyinfo object?
psudo code:
propertyinfoObject = Text
myobject.toCommand(propertyinfoObject)
The psudo code above should do the same as
myobject.Text
My goal is to create a simpel Properties form that will work on any object (Later I will use keywords to filter out what options I want the use to see).
My real code
Public Class PropertiesForm
Dim propertyInfoVar() As PropertyInfo
Dim Properties As New Form2
Dim listItem As New ListViewItem
Dim stringarray() As String
Public Sub New(ByRef sender As Object)
propertyInfoVar = sender.GetType().GetProperties()
For Each p In propertyInfoVar
stringarray = {p.Name.ToString, #INSERT VALUE SOMEHOW HERE#}
listItem = New ListViewItem(stringarray)
Properties.ListView1.Items.Add(listItem)
Next
Properties.Visible = True
End Sub
EDIT
Just use propertyGrid as suggested below!

The standard PropertyGrid already does all that for you. Filtering properties is not so obvious, here's how:
The control includes a BrowsableAttributes property which allows you to specify that only properties with the specified attribute value should be shown. You can use existing attributes, or custom ones. This is specifically for tagging visible props:
<AttributeUsage(AttributeTargets.Property)>
Public Class PropertyGridBrowsableAttribute
Inherits Attribute
Public Property Browsable As Boolean
Public Sub New(b As Boolean)
Browsable = b
End Sub
End Class
Apply it to an Employee class to hide pay rates or anything else:
Public Class Employee
<PropertyGridBrowsable(True)>
Public Property FirstName As String
...
<PropertyGridBrowsable(False)>
Public Property PayRate As Decimal
<PropertyGridBrowsable(False)>
Public Property NationalInsuranceNumber As String
Test code:
Dim emp As New Employee With {.Dept = EmpDept.Manager,
.FirstName = "Ziggy",
.PayRate = 568.98D,
...
.NationalInsuranceNumber = "1234567"
}
propGrid.BrowsableAttributes = New AttributeCollection(New PropertyGridBrowsableAttribute(True))
propGrid.SelectedObject = emp
BrowsableAttributes is a collection, so you can add several.

Related

Binding DatagridView to List Provides "Extra" columns at runtime

I have a list of objects called "TournamentPlayers" (derived from a class "PlayerInfo") in my project.
I have applied the following code to bind the lstTournPlayers to a DataGridView:
' Bind List of TournamentPlayers to Datagridview
Dim bindingList = New BindingList(Of TournamentPlayers)(lstTournPlayers)
Dim source = New BindingSource(bindingList, Nothing)
dgvPlayers.DataSource = source
dgvMembershipNo.DataPropertyName = "strMembershipNo"
dgvPlayerName.DataPropertyName = "strMembershipName"
Found from an answer here on SO, but repurposed: https://stackoverflow.com/a/16695971/692250
However, I noticed that after setting up the columns within the datagrid view, I get this weird column heading now:
My question is: how can I bind the parts of the list to this datagridview.
For anyone interested here is the schema of the list:
Public Class PlayerInfo
Public strPlayerFirstName As String
Public strPlayerLastName As String
Public strMembershipNo As String
Public strMembershipName As String
End Class
Public Class TournamentPlayers : Inherits PlayerInfo
Public intStatus As Integer = 0
Public intByeRounds As Integer
Public intTeamID As Integer
End Class

Using classes for JSON serialization

All,
I need some help with understanding how classes can work with vb.NET and JSON.NET. I'm completely new to this. I've tried searching for answers, but I'm probably not asking the right questions. Here's my dilemma:
I have a JSON that I need to send to a REST API.
{
"paInfo":[
{
"providerAccountName":"someClient",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
},
{
"providerAccountName":"someClient1",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
}
],
"hubAccountName":"test"
}
I ran this through https://jsonutils.com/ to build my class as:
Public Class PaInfo
Public Property providerAccountName As String
Public Property providerAccountDescription As String
Public Property providerName As String
Public Property externalProviderIdentifier As String
End Class
Public Class addHubAcct
Public Property paInfo As PaInfo()
Public Property hubAccountName As String
End Class
From there, I'm trying to assign values to the class properties, but I don't quite understand how to pass the values for PaInfo to the property. Below is a snippet of code I'm using to assign values. If I try to assign a.paInfo = p, it errors:
error BC30311: Value of type 'PaInfo' cannot be converted to
'PaInfo()'
If I don't pass anything through to a.paInfo, I get a zero-length string in the JSON serialization.
Private Sub serializeAcct()
Dim p As New PaInfo
Dim a As New addHubAcct
p.providerAccountName = "Test\name'This ""that and the other'"
p.providerAccountDescription = "acct desc"
p.providerName = "tester"
p.externalProviderIdentifier = "123456"
a.hubAccountName = "Tester"
a.paInfo = p 'Here's my hangup
Dim o As String = JsonConvert.SerializeObject(a)
Dim deserializedProduct As addHubAcct = JsonConvert.DeserializeObject(Of addHubAcct)(o)
Stop
End Sub
?o.tostring,nq
{"paInfo":null,"hubAccountName":"Tester"}
Change the addHubAcct class like this:
Public Class addHubAcct
Public Property paInfo As New List(Of PaInfo)()
Public Property hubAccountName As String
End Class
And then change the bad line in serializeAcct() like this:
a.paInfo.Add(p)
You likely have other problems as well, but that should get you past the current obstacle.
Using List and .ToArray is what I was missing with my original code.
Private Sub serializeAcct()
Dim p1 As New PaInfo
Dim ps As New List(Of PaInfo)
Dim a As New addHubAcct
p1.providerAccountName = "Test\name'This ""that and the other'"
p1.providerAccountDescription = "acct desc"
p1.providerName = "tester"
p1.externalProviderIdentifier = "123456"
ps.Add(p1)
a.hubAccountName = "Tester"
a.paInfo = ps.ToArray
Dim o As String = JsonConvert.SerializeObject(a)
End Sub

For a combobox with item = a datarow, how to point ValueMember to one of it's columns

I add items to a combobox like this:
For each R as DataRow in MyDataTable.Rows
If R("ID") > 10 then MyCombo.Items.Add(R)
Next
And now I need to set the DisplayMember and ValueMember to a column of the datarow:
MyCombo.ValueMember = R("ID")
MyCombo.DisplayMember = R("Name")
I know it doesn't make sence to to use "R" as it doesn't reference to anything at this point but it's just to make an indication of what I mean ;-)
The documentation for ValueMember says:
"A String representing a single property name of the DataSource property value, or a hierarchy of period-delimited property names that resolves to a property name of the final data-bound object"
I know I can add the rows to a new datatable and set it to the DataSource, but as you can add any object to the combobox items, it would be nice to use the rows directly, just can't figures out how to make a reference the particular column as a string.?
Maybe you cannot use a row object directly. I guess to use Valuemember you need your item objects to be wrapped in a collection which implement an ilist interface.
In the old MS-Access days combobox items had natively Display- and ValueMember properties, I've always missed that in the .Net combobox control.
My work-around is to use this class, which then can be used for all your ComboBoxes:
Class oComboItems
Public items As New List(Of oDVpairs)
Class oDVpairs
Implements IComparable(Of oDVpairs)
Private myDM As String
Private myVM As Object
Sub New(DM As String, VM As Object)
myDM = DM
myVM = VM
End Sub
Public ReadOnly Property DM() As String
Get
Return myDM
End Get
End Property
Public ReadOnly Property VM() As Object
Get
Return myVM
End Get
End Property
Public Function CompareTo(other As oDVpairs) As Integer Implements IComparable(Of oDVpairs).CompareTo
Return Me.myDM.CompareTo(other.myDM)
End Function
End Class
Public Sub AddItems(DisplayMember As String, ValueMemeber As Object)
items.Add(New oDVpairs(DisplayMember, ValueMemeber))
End Sub
Public ReadOnly Property DisplayMember() As String
Get
Return "DM"
End Get
End Property
Public ReadOnly Property ValueMember() As Object
Get
Return "VM"
End Get
End Property
End Class
And now add my datarows(or any other objects) to the ComboBox:
Dim CI As New oComboItems
For Each R As DataRow In DT_U.Rows
If R("medlnr") > 10 Then
CI.AddItems(R("name"), R("ID"))
end if
Next
CI.items.Sort()
MyCombo.DataSource = CI.Items
MyCombo.DisplayMember = CI.DisplayMember
MyCombo.ValueMember = CI.ValueMember

Returning Class Object from Inherited class

I'm trying to teach myself reflection and have been googling but I can't wrap my head around it entirely. I created a class called DataClass which contains a method called GetClassFromDB as you can see below, which will be inherited from multiple classes.
What I am attempting to do is have my dataclass read the TableName property that is defined within objResults. Once I pull in the tablename from objResults I would query the SQL database for a dataset. Once I have the dataset I would create a new object of the same TYPE inheriting this class (Which will be different types) and populate it from the dataset. Once I have the newly populated class I will return it for use.
I believe I have gotten most of the way there properly (Please correct me if there is a better way), but my real question is this. How can I create a new class of the type thats deriving that class from that string name that I getting in my code, or the type. I would want to have all the accessible properties from objResults available.
Namespace MyApp
Public Class DataClass
Private _TableName As String
Private _Name As String
Overridable ReadOnly Property TableName As String
Get
Return _TableName
End Get
End Property
Public Overloads Function GetClassFromDB() As Object
Try
Dim BaseObject As New Object
'Get the object name
Dim objName As String = MyBase.GetType().Name
'Gets the type thats calling this method
Dim objDerived As Type = MyBase.GetType()
'Get the property info to request the tablename from the derived class
Dim TableName As PropertyInfo = objDerived.GetProperty("TableName")
Dim TableNameString As String = TableName.GetValue(Me, Nothing).ToString
'Once I get the table name from objResults I can perform the SQL
Dim QueryResults as DataSet = SQLiteCLass.Query("Select * FROM TableNameString")
'Once I get data from the SQL I want to create a new object of the type deriving this method.
'In this example is objResults
Dim NewObject as objDerived
'Now I can fill my new object with the results and return it as an object
'THIS IS MY QUESTION - How can I create a new object of the TYPE that I receive from Reflection
Return False
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
and this is a sample class that would inherit my dataclass.
Public Class objResults
Inherits MyApp.DataClass
Private _GameID As Guid
Public Property GameID As Guid
Get
Return _GameID
End Get
Set(ByVal value As Guid)
_GameID = value
End Set
End Property
Public Overrides ReadOnly Property TableName As String
Get
Return "This is my tablename"
End Get
End Property
End Class
and this is how I would use this in code.
Dim objResult as New objResults
Dim TodaysResult as objResultsCollection
TodaysResult = objResult.GetClassFromDB()

Accessing Items in a Collection from a Class

-EDIT Fixed
I was missing one thing and doing one thing wrong. First I was missing a function to access the collection by index. And I should of been using a for Loop instead of a for each loop in my module code
I forgot to add this to the collection class
Public Function GetPayRecords(ByVal index As Variant) As PayRecords
Set GetPayRecords = pObjCol.item(index)
End Function
and replaced
For Each vItem In .GetPayRecords
....code to do stuff
Next vItem
with this in the module
Dim x As Integer
For x = 1 To .Count
Debug.Print .GetPayRecords(x).PY_PayRecord.CEOCompanyID
Debug.Print .GetPayRecords(x).PY_PayRecord.OrigBankID
Next x
I'm writing a program that has 8 Classes. Each class represents a specific record type.
I have an overall Class that contains those 8 classes which is for simplicity when coding in the Module. I only have to declare one class which gives me access to all 8 classes. I have a collection which contains all the records types. Once all the logic of loading the individual records is complete they get added to the collection. This all works perfectly and I can see all the records in the collection. The final step, which happens to be where i'm having the problem, I need to extract each item within the collection by record type and write it to a csv. The problem I encounter is trying to iterate through each record.
Here's how the structure looks
Classes
clsAllRecordTypes
clsRecordType1
clsRecordType2
...
clsRecordType8
Collection
clsColRecords
The problem is in the retrieval
Module
Dim PayRecord As PayRecords 'Class of Classes
Dim PayRecordList As bankCollection
...code to load all the payrecords
With payrecordlist
Foreach vItem in .pObjCol
debug.print .pObjCol.Item(?) ' not sure why i can't see all 8
next vItem
End With
When I add vItem to the watch I can see each and every record type filled up with information but yet i Can not access it. Below is the Class of classes and collection
Class of Classes
Option Explicit
'This class is a representation of all the record types that apply to our Payment Manager
'It aggregates all the record types (classes) into one class. That one class is used in the main processing module for simplicty
'
Private pPayRecord As New PayRecord
Private pPNAR_OP As New PNAR_OP
Private pPNAR_RP As New PNAR_RP
Private pSuppACHREC As New SuppACHRec
Private pSuppCCRRec As New SuppCCRRec
Private pSuppCHKRec As New SuppCHKRec
Private pDocumentDelieveryRec As New DocumentDeliveryRecord
Private pInvoiceRecords As New InvoiceRecords
Public Property Get PY_PayRecord() As PayRecord
Set PY_PayRecord = pPayRecord
End Property
Public Property Let PY_PayRecord(ByVal newPayRecord As PayRecord)
Set pPayRecord = newPayRecord
End Property
Public Property Get PA_PNAR_OP() As PNAR_OP
Set PA_PNAR_OP = pPNAR_OP
End Property
Public Property Let PA_PNAR_OP(ByVal newPNAR_OP_Record As PNAR_OP)
Set pPNAR_OP = newPNAR_OP_Record
End Property
Public Property Get PA_PNAR_RP() As PNAR_RP
Set PA_PNAR_RP = pPNAR_RP
End Property
Public Property Let PA_PNAR_RP(ByVal newPNAR_RP_Record As PNAR_RP)
Set pPNAR_RP = newPNAR_RP_Record
End Property
Public Property Get AC_SuppACH() As SuppACHRec
Set AC_SuppACH = pSuppACHREC
End Property
Public Property Let AC_SuppACH(ByVal newSuppACH_Record As SuppACHRec)
Set pSuppACHREC = newSuppACH_Record
End Property
Public Property Get AC_SuppCCR() As SuppCCRRec
Set AC_SuppCCR = pSuppCCRRec
End Property
Public Property Let AC_SuppCCR(ByVal newSuppCCR_Record As SuppCCRRec)
Set pSuppCCRRec = newSuppCCR_Record
End Property
Public Property Get AC_SuppCHK() As SuppCHKRec
Set AC_SuppCHK = pSuppCHKRec
End Property
Public Property Let AC_SuppCHK(ByVal newSuppCHK_Record As SuppCHKRec)
Set pSuppCHKRec = newSuppCHK_Record
End Property
Public Property Get DocumentDeliveryRecord() As DocumentDeliveryRecord
Set DocumentDeliveryRecord = pDocumentDelieveryRec
End Property
Public Property Let DocumentDeliveryRecord(ByVal newDocumentDeliveryRecord As DocumentDeliveryRecord)
Set pDocumentDelieveryRec = newDocumentDeliveryRecord
End Property
Public Property Get InvoiceRecords() As InvoiceRecords
Set InvoiceRecords = pInvoiceRecords
End Property
Public Property Let InvoiceRecords(ByVal newInvoiceRecord As InvoiceRecords)
Set pInvoiceRecords = newInvoiceRecord
End Property
Collection Class
Option Explicit
Private pHeaderRec As New HeaderRec
Private pNewPayRecords As New PayRecords
Public pObjCol As Collection
Private pTrailerRec As New TrailerRec
Private Sub Class_Initialize()
Set pObjCol = New Collection
End Sub
Private Sub Class_Terminate()
Set pObjCol = Nothing
End Sub
Public Property Get HD_HeaderRecord() As HeaderRec
Set HD_HeaderRecord = pHeaderRec
End Property
Public Property Let HD_HeaderRecord(ByVal newHeaderRecord As HeaderRec)
Set pHeaderRec = newHeaderRecord
End Property
Sub Add(ByVal newPayRecs As PayRecords)
pObjCol.Add newPayRecs
End Sub
Property Get Count() As Long
Count = pObjCol.Count
End Property
Public Property Get TR_TrailerRecord() As TrailerRec
Set TR_TrailerRecord = pTrailerRec
End Property
Public Property Let TR_TrailerRecord(ByVal newTrailer_Record As TrailerRec)
Set pTrailerRec = newTrailer_Record
End Property
I'm sorry if this doesn't help, because your explanation is hard to follow. But, I'll assume that you are saying that you have an object of type Payrecords, which contains references to seven other objects of types PNAR_OP, PNAR_RP, etc. Each of these latter objects contain "20-30 fields" that you want to get at. You ask how to loop through all of these.
A simple way to do that is to use an array. Yes, you can foreach through Collections or (better yet) Dictionaries, but arrays work, they're easy to understand, and they were iterating through objects when Collections were running around in diapers.
Let your Payrecords have a property of type Object(6). When you initialize it, instantiate one of each of the seven objects and add it to the array (for example, "Set myPayrecordsObjects(3) = New SubCCRRec" and so on). To loop through, just use a for next loop to loop through the 7 objects.
Since you provide no information about how you structure your "fields" within these objects, I'll recommend that you iterate through the Fields collection of the ADO object to loop through those. (If you're not using the ADO Fields collection, well, your attention to detail gets mine in return.)