Get ValueMember of Selected item in ListBox - vb.net

I've seen a couple of posts asking a similar question but I have not been able to duplicate the answers in my code successfully.
The following code adds items and their value member to a list box.
Public Shared Sub ListFiles(hTab As Hashtable)
Debug.Print("create file and key" & Now)
Dim Enumerator As IDictionaryEnumerator
Enumerator = hTab.GetEnumerator()
Dim MyKeys As ICollection
Dim Key As Object
MyKeys = hTab.Keys()
If (hTab.Count > 0) Then
For Each Key In MyKeys
Dim sfileName As String = hTab(Key)
Dim first As Integer = sfileName.IndexOf("_")
Dim last As Integer = sfileName.LastIndexOfAny("_")
Dim first2 = (first + 1)
Dim splitFile = sfileName.Substring(first2)
frmViewFiles.ListBox1.Items.Add(splitFile)
frmViewFiles.ListBox1.ValueMember = Key
frmViewFiles.ListBox1.SelectedValue = Key
Next
End If
End Sub
When I run my code to get the selected items value member
Dim file = ListBox1.ValueMember.ToString()
I can acess the first item I choose but subsequent selections dont change the value member to that of the selected item.
Please direct me.
Thank you for your answers. this is my new code:
Public Shared Sub runListFiles(CustomerId As String)
Dim cfp As New CloudFilesProvider(cloudId)
Dim containerObjectList As IEnumerable(Of ContainerObject) = cfp.ListObjects(container:="EstherTest", identity:=cloudId, prefix:=CustomerId & "_")
For Each file As ContainerObject In containerObjectList
Dim sFullFileName As String = file.Name
Dim first As Integer = sFullFileName.IndexOf("_")
Dim first2 = (first + 1)
Dim splitFile = sFullFileName.Substring(first2)
'frmViewFiles.ListBox1.Items.Add(splitFile)
'frmViewFiles.ListBox1.ValueMember = sFullFileName
Dim fb = New myFile
fb.FileName = splitFile
fb.FullPath = sFullFileName
frmViewFiles.ListBox1.Items.Add(fb)
frmViewFiles.ListBox1.DisplayMember = fb.FileName
frmViewFiles.ListBox1.ValueMember = fb.FullPath
This is my class:
Public Class myFile
Public Property FileName As String
Public Property FullPath As String
Public Sub New(f As String, b As String)
FileName = f
FullPath = b
End Sub
End Class
Please see my comment below and assist

ValueMember is supposed to indicate the property name of an object added to the Items collection: the property to use as the actual value for the items in the ListControl.
You are not adding objects to the control, so Key from the hashtable is meaningless as the ValueMember. Your post references a file variable in passing, so I will assume this revolves around showing the filename while wanting to get the full pathname when selected/clicked. WebForms/Winforms/WPF was not indicated, I am assuming WinForms:
Public Class myFile
Public Property FileName As String
Public Property FullPath As String
Public Property FileSize As Int64 ' just so there is something else
Public Sub New(f as String, p as String, s as Int64)
FileName = f
FullPath = b
FileSize = s
End Sub
End Class
Lets say we want to add some of these to a ListBox, for each item added we want FileName to display as the text, but want to get them back by FullPath:
Dim f As myFile
' assume these come from a fileinfo
For Each fi as FileInfo in DirectoryInfo.GetFiles(searchFor)
f = New myFile
f.FileName = fi.Name
f.FullPath = fi.FullPath
f.FileSize = fi.Length
' myFile accepts all the prop values in the constructor
' so creating a new one could also be written as:
' f = New myFile(fi.Name, fi.FullPath, fi.Length)
myListBox.Items.Add(f)
Next n
If the myFile objects were stored to a List(of myFile) rather than adding them to the control, we can bind the List as the DataSource and not have to iterate or copy:
mylistBox.DataSource = myFileList
Either way, Display- and ValueMember refer to the property names we wish to use:
myListBox.DisplayMember = "FileName" ' indicate property name of obj to SHOW
myListBox.ValueMember = "FullPath" ' prop name of object to return
When you select a listbox item, myListBox.SelectedValue would refer to the FullPath of the myFile object clicked on. The SelectedIndex would still refer to the index of the item in the list.
tl;dr
ValueMember and DisplayMember refers to the Property Names of Objects represented in the list.
Note:

I know this is many years later, but still relevant information.
It took me a while to parse what was said above, until I grokked it fully, so I thought it might help if I restated it slightly.
When you select a listbox item,
myListBox.SelectedValue is the contents of the field, myListBox.ValueMember. ValueMember contains the Field Name, SelectedValue contains the contents of the field.
myListBox.SelectedItem is the contents of the field myListBox.DisplayMember. DisplayMember contains the field name and SelectedItem contains the value of the field.
The SelectedIndex refers to the index of the item in the list. To see which item is selected, reference myListBox.SelectedIndex. You can, for example, change the selection to the last item in the list by using myListBox.SelectedIndex = myListBox.Items.Count - 1
If you want to display the values, then
Console.WriteLine("The value of {0} is {1}",myListBoxDisplayMember,myListBox.SelectedItem)
Console.WriteLine("The Value of {0} is {1}",myListBox.ValueMember,myListBox.SelectedValue)

Related

About Casting in a Class property in VB.Net

Is it possible to cast a sting in a class property?
what i want to do is that from 'My' class i can fetch the Form's Text properties. but for every form i have to provide the form name statically. I want to do it dyanamically. What i tried is here
Dim frmName As New Object
frmName = Name.ToString()
Dim frmProperty As String
frmProperty = "My.Forms." & frmName & ".Text"
frmNameLabelControl.Text = frmProperty
but at the Front-End it displays 'My.Forms.Form1.Text'
I think that all you need is the following code. But you need to create the equivalent of frmNameLabelControl in the same order in every form. For example to be the last label you created in every form
Dim FormsCount As Integer = My.Application.OpenForms.Count
Dim frmProperty As String
Dim lblContrIndex As Integer = 0 ' Number of label creation in descending order
For i As Integer = 0 To FormsCount - 1
frmProperty = My.Application.OpenForms.Item(i).Text
My.Application.OpenForms.Item(i).Controls.OfType(Of Label).ElementAt(lblContrIndex).Text = frmProperty
Next

Listview - add File type & Last modified Subitems

I'm trying to add "file type" and "last modified" to my Listview when adding items in It same as in Explorer, but I don't find what property should be assigned to SubItem. Here is my code:
For Each MyFile As IO.FileInfo In ItemDirectory.GetFiles
Dim lvi As New ListViewItem
lvi.Tag = mFile.FullName
lvi.Text = mFile.Name
lvi.ImageKey = CacheShellIcon(mFile.FullName)
Listview1.Items.Add(lvi)
lvi.SubItems.Add("File type ??")
lvi.SubItems.Add(mFile.LastAccessTime.ToShortDateString & " " & mFile.LastAccessTime.ToShortTimeString) 'This isn't same as last modified ?
Next
If somebody knows how to do It please let me know, I want to have this in my Details view.
The linked answer provides an all-purpose way to get all the extended properties. With 300+ elements in newer Windows versions it is clearly overkill to fetch them all if you are only interested in one or two. This returns just the file type. A better approach might be to pass a "shopping list" of desired property names.
As before, you need to add a reference to Microsoft Shell Controls and Automation or Microsoft Shell Folder View Router based on your OS version.
Imports Shell32
Imports SHDocVw
Partial Friend Class Shell32Methods
Friend Shared Function GetShellFileProperty(filepath As String, index As Int32) As String
Dim shell As New Shell32.Shell
Dim shFolder As Shell32.Folder
shFolder = shell.NameSpace(Path.GetDirectoryName(filepath))
' get shell data for this file, cast to folder item
Dim shFolderItem = DirectCast(shFolder.Items().Item(Path.GetFileName(filepath)),
Shell32.ShellFolderItem)
If shFolderItem IsNot Nothing Then
Return shFolder.GetDetailsOf(shFolderItem, index)
Else
Return String.Empty
End If
End Function
...
End Class
Usage:
Dim lvi As ListViewItem
Dim fileType As String
For Each f As String In Directory.EnumerateFiles("C:\Temp\ShellTest")
fileType = Shell32Methods.GetShellFileProperty(f, 9)
lvi = New ListViewItem
lvi.Text = Path.GetFileName(f)
lvi.SubItems.Add(fileType)
lvFiles.Items.Add(lvi)
Next
Ideally, you'd want to create an Enum for the properties so the code could avoid magic numbers:
fileType = Shell32Methods.GetShellFileProperty(f, Shell32FileProps.FileType)
As noted elsewhere, the index of the ones >260 or so can change depending on the OS version. That could be easily modified to accept an Enum/Int array and return a list of values so as to prevent iterating all 300+ propertied to get one or three.
For filetype you can use lvi.SubItems.Add(MyFile.Extension)
and for the "last modified" date, of course the last modified! :D
lvi.SubItems.Add(MyFile.LastWriteTime.ToShortDateString)
Last write and last access are not the same ;)
I figured out another solution, I think this one is easier, at least for me :
Public Function ExProperty(filepath As String, PropertyItem As Integer)
Dim arrHeaders As New List(Of String)()
Dim shell As New Shell
Dim rFolder As Folder = shell.[NameSpace](Path.GetDirectoryName(filepath))
Dim rFiles As FolderItem = rFolder.ParseName(Path.GetFileName(filepath))
'I needed only File type so I looped to 2 only (2 is the file type in my case - Windows 10 -
' to see all available properties do a loop
' 0 To Short.MaxValue - 1" and then extract whatever property you like)
For i As Integer = 0 To 2
Dim value As String = rFolder.GetDetailsOf(rFiles, i).Trim()
arrHeaders.Add(value)
Next
Dim DesiredProperty As String
DesiredProperty = arrHeaders.Item(PropertyItem)
Return DesiredProperty
End Function
Usage with Listview just simply (this adds File type subitem):
Listview1_Item.SubItems.Add(ExProperty(filepath, 2))
As in all solutions, a reference to Microsoft Shell Controls and Automation must be set.

Readonly in keyvaluepair

Well I have created a program that takes some files (Mp3) and change their tags
recently I wanted to add some new Subs (like: Take the songs name and make every letter in it upercase). The problem is that i use a list with its items to be keyvaluepairs
Public MP3List As New List(Of KeyValuePair(Of String, String))
When i tried to edit the key or value of any Item in that list i get an error (That this is READONLY)
Example:
For Each Song In MP3List
Song.Key = "Something"
Next
I add items like this :
Private Function OpenAFile()
Dim MP3List1 = MP3List
Dim oFileDialog As New OpenFileDialog
oFileDialog.Title = "Επέλεξε ένα MP3 Άρχειο"
oFileDialog.Filter = "MP3 Files|*.mp3|All Files|*.*"
oFileDialog.Multiselect = True
Dim Path As String = ""
Dim Name As String = ""
Dim NewPair As New KeyValuePair(Of String, String)
If oFileDialog.ShowDialog = Windows.Forms.DialogResult.OK Then
For Each sPath In oFileDialog.FileNames
Path = New String(sPath)
Name = New String(Strings.Split(Path, "\").ToList(Strings.Split(Path, "\").ToList.Count - 1))
NewPair = New KeyValuePair(Of String, String)(Name, Path)
If Not MP3List1.Contains(NewPair) Then MP3List1.Add(NewPair)
Next
End If
Return MP3List1
End Function
So the idea is this: Each time i press A button to add a song it will run the function OpenAFile() and it was working fine then . Now that i want to change a key or value i get this error
Thanks for the Help and sorry for bad english
The Keys in a KeyValuePair are readonly because they are often used as the key in a hash table. Changing the key would cause issues where you would lose your item in the hash.
If you want to do something like this, you could always create your own data type that stores a key and value. An overly simplified example would be as follows.
Public Structure PathNamePair
Public Property Path As String
Public Property Name As String
Public Sub New(path As String, name As String)
Me.Path = path
Me.Name = name
End Sub
End Structure
I will note that in order to get better performance with your Contains method, you should also implement IEquatable(Of T), but that's probably beyond the scope of this question. I will also note that it is not best practice to have a ValueType (Structure) that is mutable.

Looping through a list gives me repeation of items, xml serializer

I have two lists. Both are made of structures I have defined, and this loop is meant to convert the two. I.e., convert and then add to the second list of the other type. Here is what I have:
Dim tempList As New List(Of CameraTemplateProduct)
tempList.Clear()
For j As Integer = 0 To EditCamerasNEW.templateList.Count - 1
'Set up product object.
Dim temp As New CameraTemplateProduct()
'equal properties
temp.Name = EditCamerasNEW.templateList.Item(j).mac
temp.Bitrate = EditCamerasNEW.templateList.Item(j).bitrate
temp.CamDate = EditCamerasNEW.templateList.Item(j).camdate
temp.CamTime = EditCamerasNEW.templateList.Item(j).camtime
temp.Encoder = EditCamerasNEW.templateList.Item(j).encoder
temp.FPS = EditCamerasNEW.templateList.Item(j).fps
temp.Hostname = EditCamerasNEW.templateList.Item(j).hostname
temp.MD = CBool(EditCamerasNEW.templateList.Item(j).MDen)
temp.OSD = CBool(EditCamerasNEW.templateList.Item(j).OSD)
temp.Resolution = EditCamerasNEW.templateList.Item(j).res
tempList.Add(temp)
Next
'Serialize object to a text file.
Dim x As New XmlSerializer((tempList.GetType))
x.Serialize(objStreamWriter, tempList)
Very straight forward. Copy over each property, then add it to the list. When I'm in the loop, temp's values copy over well. The values are exactly the same as the item in TemplateList. When I step through the loop, tempList is exactly what I expect it to be. Three distinct structures. But after wards I get the exact same number of items, but copies of one of them in my list.
However, the line right after the next loop, the tempList instead is the exact same count as templateList, but each value is exactly the same. So every item has the same name, MD, encoder, etc value.
What I've tried: I've tried changing the line after the next to
Dim x As New XmlSerializer((GetType(List(Of CameraTemplateProduct))))
but it gives the same result.
What am I doing wrong? Is there anything the "templist.gettype" is doing to cause this?
EDIT:
I have found that the temp is not changing property values when it loops, so it stays stuck at the first loop values. Is there a better way to clear or set it? I tried setting it to Nothing, but it gave me NULL assignment error.
EDIT2: So following the comments,
I checked to see if the templatelist items were changing. I added a
Dim test = EditCamerasNEW.templateList(j).mac
for each loop to see that it changed. The value did change. I set the rest of the "templatelist.item(j).x" to just "templatelist(j)" as above, but it didn't stop it from creating a list of repeated values.
EDIT3 Tried the below method to no avail. I'm thinking it is possibly when I create the templist of my class. It may not know how to create a list of the product? I will take any help on that.
tempList.Add(New CameraTemplateProduct With {.Name = EditCamerasNEW.templateList(j).mac, _
.Bitrate = EditCamerasNEW.templateList(j).bitrate, _
.CamDate = EditCamerasNEW.templateList(j).camdate, _
.CamTime = EditCamerasNEW.templateList(j).camtime, _
.Encoder = EditCamerasNEW.templateList(j).encoder, _
.FPS = EditCamerasNEW.templateList(j).fps, _
.Hostname = EditCamerasNEW.templateList(j).hostname, _
.MD = EditCamerasNEW.templateList(j).MDen, _
.OSD = EditCamerasNEW.templateList(j).OSD, _
.Resolution = EditCamerasNEW.templateList(j).res})
Here's a portion of the CameraTemplateProduct definition. It's pretty normal:
Public Class CameraTemplateProduct
Public Shared strhostname As String
Public Shared bOSD As Boolean
Public Shared strbitrate As String
Public Shared strencoder As String
Public Shared bMDen As Boolean 'motion detection enabled
Public Shared strres As String
Public Shared intfps As Integer
Public Shared strcamtime As String
Public Shared strcamdate As String
Public Shared strTemplateName As String
'grab properties
Public Property Name() As String
Get
Name = strTemplateName
End Get
Set(ByVal Value As String)
strTemplateName = Value
End Set
End Property
Public Property Hostname() As String
Get
Hostname = strhostname
End Get
Set(ByVal Value As String)
strhostname = Value
End Set
End Property
Public Property OSD() As Boolean
Get
OSD = bOSD
End Get
Set(ByVal Value As Boolean)
bOSD = Value
End Set
End Property
' code continues

Adding file path to listbox item

I'm trying to store the file path in a tag of a listbox item.
I'm using the below to search through and add the desired folder name to the list box
I've added the ListBox1.Tag = sDir line to above the first Next and when I step thorugh the code the value of sDir appears to hold the path however if I create a simple Double click event that pops up a message box with the file path in it only shows the first folder name in the list.
Any tips or advice - I basically want to select a Listbox item and have it point to its path!
Thanks
For Each Dir As String In System.IO.Directory.GetDirectories("c:\Working")
Dim dirInfo As New System.IO.DirectoryInfo(Dir)
For Each sDir As String In System.IO.Directory.GetDirectories(dirInfo.ToString)
Dim sdirInfo As New System.IO.DirectoryInfo(sDir)
ListBox1.Items.Add(sdirInfo.Name)
ListBox1.Tag = sDir
Next
Next
You can store objects as items, so a small class to store item info:
Public Class myClass
Public Property FileName as String
Public Property PathName As String
Public Foo As Integer
' class is invalid w/o file and path:
Public Sub New(fName As String, pName As String)
FileName = FName
PathName = pName
End Sub
' this will cause the filename to show in the listbox
Public Overrides Function ToString() AS String
Return FileName
End Sub
End Class
You can now store these in the listbox as you load/find them:
Dim El as MyClass ' temp var for posting to listbox
' in the loop:
El = New MyClass(filename, pathName) ' use names from your Dir/File objects
ListBox1.Items.Add(El)
and to get it back:
' INDEX_TO_READ is a dummy var of the index you want to get
' SelectedItem will also work
thisFile = Ctype(ListBox1.Items(INDEX_TO_READ), MyClass).FileName
thisPath = Ctype(ListBox1.Items(INDEX_TO_READ), MyClass).PathName
' or:
Dim aFile As myClass = Ctype(ListBox1.Items(INDEX_TO_READ), MyClass)