Unable to cast custom listviewitem class in vb.net - vb.net

This is a followup question to another question I asked earlier. I thought I had everything I needed, but I'm running into another issue. I'm trying to use a custom listviewitem class that attaches additional information to a lisview item. Here is the class:
Public Class albumListViewItem
Inherits ListViewItem
Public hash As String
Public id As Integer
Public provider As String
Public providerID As String
Public providerURL As String
Public providerArtistID As String
Public albumName As String
Public albumType As String
Public numTracks As Integer
Public imageURLs() As String
Public genres() As String
Public styles() As String
Public label As String
Public year As String
Public country As String
Public rating As String
Public editorsPick As Boolean
Public sampleStreamURL As String
Public providerReview As String
End Class
When I try to cast a listviewitem to my custom class like this:
Dim albumItem As albumListViewItem = CType(lsvHidden.items.item(0), albumListViewItem)
I get the following error, "Unable to cast object of type 'System.Windows.Forms.ListViewItem' to type 'AudioMatic.albumListViewItem'."
What am I missing here?

From your previous question and this one, I think a better fit for your problem would be to use a regular ListViewItem and store the accessory information in ListViewItem.Tag
You can do
Dim listViewItem As New ListViewItem("SomeText")
Dim albumInfo As New albumListViewItem()
albumInfo.albumName = "SomeAlbum"
...
listViewItem.Tag = albumInfo
listView1.Items.Add(listViewItem)
and then retrieve it like this
Dim selectedItem As ListViewItem = listView1.SelectedItems(0).Item
Dim alubmInfo As albumListViewItem = TryCast(selectedItem.Tag, alubmListViewItem)
Dim albumName as String = albumInfo.albumName
see if this solution will work for you.

If you step through the code and watch the variable "lsvHidden.items.item(0)" you should be able to first tell if it is in fact of type "albumListViewItem" or something else. Are you sure it was albumListViewItem that was added to the list in the first place?
Some alternatives to what you are doing;
1. You can implement an object and store it in the tag of the ListViewItem.
2. The following article seems to describe another approach of adding Columns to the listview to allow storing extra information on the listview itself; http://www.codeproject.com/KB/list/ListViewExtendedItem.aspx
I can appreciate your situation as I would have expected that to work. And I can see advantages and reasons for doing it that way as well. Not sure if the code project sample is adaptable to what you need, so you'll need to review the concept.

The working code:
Public Class albumListViewItem
Inherits ListViewItem
Public hash As String
Public id As Integer
Public provider As String
Public providerID As String
Public providerURL As String
Public providerArtistID As String
Public albumName As String
Public albumType As String
Public numTracks As Integer
Public imageURLs() As String
Public genres() As String
Public styles() As String
Public label As String
Public year As String
Public country As String
Public rating As String
Public editorsPick As Boolean
Public sampleStreamURL As String
Public providerReview As String
End Class
Storing information using listviewitem.tag:
Dim listViewItem As New ListViewItem("SomeText")
Dim albumItem As New albumListViewItem
albumItem.albumName = "Test Album"
albumItem.id = "testid"
albumItem.Text = albumItem.albumName
albumItem.year = "2011"
albumItem.numTracks = 10
'....
listViewItem.Tag = albumItem
'add viewable items to listview
albumItem.SubItems.Add(albumItem.year)
albumItem.SubItems.Add(albumItem.numTracks)
'....
ListView1.Items.Add(albumItem)
Reading the information that was previously stored:
Dim albumInfo As albumListViewItem = CType(ListView1.SelectedItems(0), albumListViewItem)
Dim id as string = alumInfo.id

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

Refer to a Class from within a With VB.net

I have called clientdetails which I wish to return as a whole to the JSONConvert Method to Serialize for JSON.
I have created a Class that has the Property Types I require (TextA,TextB) etc.
I can refer to both TransactionCount and TransactionType because they are part of ClientDetails, however when I try to refer to TextA of Transactions it states that TextA is not a member of ClientDetails - this I know which is why I explicitly state .Transactions.TextA.
If I declare Transactions separate under a new variable then I am able to refer to them however I need them to all be declared under ClientDetails to pass to the Serializer.
Can anyone point me out what I'm doing wrong here? Still learning.
Public Class JSON
Public Shared Function SerializeObject()
Dim clientdetails As New ClientDetails() With {.TransactionCount = "1", .TransactionType = "Q", .Transactions.TextA} 'Unable to Refer to any Property of Transactions.
'Dim Trans As New Transactions()
'Trans.TextA= "Test"
Dim output As String = JsonConvert.SerializeObject(clientdetails, Newtonsoft.Json.Formatting.Indented)
Return output
End Function
End Class
Public Class ClientDetails
Public Property Transactions As New Transactions()
Public Property [TransactionType] As String
Public Property [TransactionCount] As Integer
End Class
Public Class Transactions
Public Property [RecordID] As String
Public Property No As String
Public Property TextA As String
Public Property TextB As String
Public Property Initial As String
Public Property Flag As String
Public Property Sex As String
Public Property Area As String
Public Property Type As String
Public Property IDNO As String
End Class
You can use this syntax:
Dim clientdetails As New ClientDetails() With {.TransactionCount = "1", .TransactionType = "Q", .Transactions = New Transactions() With {.TextA = "Test"}}
Or a more readable code:
Dim trans As New Transactions
trans.TextA = "Test"
Dim clientDetails As New ClientDetails()
With clientDetails
.TransactionCount = "1"
.TransactionType = "Q"
.Transactions = trans
End With

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

Access deserialize JSON and avoid var declaration

I'm completely new to vb (started about 2 hours ago) and I'm trying to convert a php application to vb to circumnavigate some unavoidable problems.
However I'm trying to get a response from a server that returns a JSON string as page source(everythng is fine untill here), my problem is that I don't understand exactly how to access the deserialized object.
This is the response:
{
"response":{
"a":"boolean",
"b":"string",
"c":"string",
"d":"string",
"e":"string",
"f":"string",
"profile":{
"h":"decimal",
"i":"string",
"l":"string",
"m":"string",
"n":"string",
"o":"string",
"p":"string",
"q":"string"
}
}
}
Current vb code:
Public Class Form1
...
Dim jsonResponse As String = New System.Net.WebClient().DownloadString(url)
Dim r As LoginReturn = JsonConvert.DeserializeObject(Of LoginReturn)(jsonResponse)
...
End Sub
Public Class LoginItem
Public a As Boolean
Public apikey As String
Public c As String
Public d As String
Public e As String
Public f As String
Public Property profile As List(Of LoginProfile)
End Class
Public Class LoginProfile
Public h As Decimal
Public i As String
Public l As String
Public m As String
Public n As String
Public o As String
Public p As String
Public q As String
End Class
Public Class LoginResponse
Public Property response As List(Of LoginItem)
End Class
Public Class LoginReturn
Public Property value As List(Of LoginResponse)
End Class
From all those infomation I only need apikey so I tried to access it with these
r.value.response.apikey
r.value(0).response.apikey
Both returns this error:
'apikey' is not a memeber of 'System.Collections.Generic.List(Of WindowsApplication1.LoginItem)'.
Previously with php I used this:
$r = json_decode(file_get_contents($url));
$_SESSION['a']=$r->response->apikey
So my questions are:
How do I access that information?
Do I need to declare all those variables even if I don't need them?
EDIT SOLUTION
'Get Json
Dim jsonResponse As String = New System.Net.WebClient().DownloadString(url)
'Parse Json
Dim r As JObject = JObject.Parse(jsonResponse)
'Access Json
GlobalVar.api = r("response")("apikey")
This will show you how to parse the raw JSON so you can pluck out the part you are interested in. Since you only want one thing, you can use JObject.Parse and forego the classes to get what you want.
' you would get it from the webclient
Dim jstr As String = File.ReadAllText("C:\Temp\logresp.json")
Dim api = obj("response")("b")
To read something else, just change the key to whatever item you want. For instance, to read "q":
Dim QItem = obj("response")("profile")("q")
Since q is a property of profile, which itself is a child of response you have to dig deeper.
If you do end up needing many things, your classes are not quite right for parsing into a class (DeserializeObject). Look at the JSON and you'll see there is no property named "APIKey". Going by position, it is called "b". This might be an artifact of changing things around for posting here, but I can only go by what is posted.

Assign direct value to object

I have several properties, for example
Public Property FIRSTNAME As New SQLString("FirstName", 50)
Public Property FULLNAME As New SQLString("Name", 50)
The SQLString object is defined as:
Public Class SQLString
Property SQL_Column As String
Property Limit As Integer
Property Value As String
Public Sub New(SQLcolumn As String, limit_ As Integer)
SQL_Column = SQLcolumn
Limit = limit_
End Sub
Public ReadOnly Property SQL_value() As String
Get
Return "'" & clean(Value, Limit) & "'"
End Get
End Property
End Class
Notice that through this method, each of my properties (e.g. FIRSTNAME) is able to have several sub properties, which is necessary.
To access them, it's simply for example FIRSTNAME.SQL_Column.
This works, however what I would like is to also be able to store a value (e.g. string data type) on the FIRSTNAME property itself, which would make accessing it like:
Dim MyFirstName As String = FIRSTNAME
Rather than:
Dim MyFirstName As String = FIRSTNAME.Value
Which is what I currently have to do.
The only way I can see to do this is to have the SQLString object be set to string (or another data type) by default, like:
Public Class SQLString As String
Obviously the above code does not work, but I'm wondering if there is an equivalent that does?
The default access modifier to a property (ie: Public, Private, etc) is the most restrictive when no access modifier is provided. In SQLString class, since there is not a Public access modifier in front of the properties in the class, they are essentially Private and not accessible from outside of the class.
Adding the access modifier to the properties should fix the issue you see:
Public Property SQL_Column As String
Public Property Limit As Integer
Public Property Value As String
Please tell me the problem for the vote downs - here is a working .NET fiddle of the proposed code changes above (https://dotnetfiddle.net/96o8qm).
Imports System
Dim p as Person = new Person()
p.FIRSTNAME = new SQLString("Test", 1)
p.FIRSTNAME.Value = "Test Value"
Console.WriteLine("Person Value: {0}", p.FIRSTNAME.Value)
Public Class Person
Public Property FIRSTNAME AS SQLString
End Class
Public Class SQLString
Public Property SQL_Column As String
Public Property Limit As Integer
Public Property Value As String
Public Sub New(SQLcolumn As String, limit_ As Integer)
SQL_Column = SQLcolumn
Limit = limit_
End Sub
Public ReadOnly Property SQL_value() As String
Get
Return ""
End Get
End Property
End Class
This yields the output:
Person Value: Test Value
The answer to your question is quite simple; add a CType widening operator.
Example:
Public Class SQLString
Public Shared Widening Operator CType(ByVal s As SQLString) As String
Return If((s Is Nothing), Nothing, s.Value)
End Operator
Public Property Value As String
End Class
Test:
Dim firstName As New SQLString() With {.Value = "Bjørn"}
Dim myName As String = firstName
Debug.WriteLine(myName)
Output (immediate window):
Bjørn