I'm new to List(Of T). Please help me.
I load my List value when system running. How to search for data that have in the List?
1. My List class
Public Class Directory
Public strdirname As String
Public strdircategory As String
Public strdirlevel As String
Public Sub New(ByVal m_dirname As String, ByVal m_dirlevel As String, ByVal m_dircat As String)
Try
strdirname = m_dirname
strdirlevel = m_dirlevel
strdircategory = m_dircat
Catch ex As Exception
MessageBox.Show("Error new instance.Ex-" & ex.Message)
End Try
End Sub
Public Property ShopName() As String
Get
Return strdirname
End Get
Set(ByVal value As String)
strdirname = value
End Set
End Property
Public Property ShopLevel() As String
Get
Return strdirlevel
End Get
Set(ByVal value As String)
strdirlevel = value
End Set
End Property
Public Property ShopCategory() As String
Get
Return strdircategory
End Get
Set(ByVal value As String)
strdircategory = value
End Set
End Property
End Class
2. My new instance for List
MyDir = New List(Of Directory)
In my search page, I want to find lets say a category eg: food & beverages. How to find all the data from the list where the strdircategory = "Food & Beverages"? Some page need to get by Level, Name also.
If I wanna search from the list, should I new the List again? Please advise.
Edited:
Dim filterSpecific As List(Of Directory) = MyDir.FindAll(Function(p As Directory) p.strdircategory = txtkey.Text)
To find an element in your List(Of T), use the Find method (for a single element):
List(Of T).Find Method
Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List.
or FindAll (for all elements):
List(Of T).FindAll Method
Retrieves all the elements that match the conditions defined by the specified predicate.
So, in your case, just use
Dim result = yourlist.FindAll(Function(d) d.strdircategory = "Food & Beverages")
You could also use the Where extension method (which returns a lazy query instead of a new List(Of T)).
Related
I'm trying to create a class with arrays in it, and I'm having issues creating the class for it...
CLASS:
Private pST(0 To 2) As String
Public Property Get ST() As String
ST() = pST()
End Property
Public Property Let ST(value() As String) '<---- ERROR HERE
pST() = value()
End Property
CODE RUN:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.ST(0) = "test"
Debug.Print foo.ST(0)
End Sub
THE ERROR:
Compile error:
Definitions of property procedures for the same property are inconsistent, or property procedure has an optional parameter, a ParamArray, or an invalid Set final parameter.
THE QUESTION:
How can I properly initialize a class with arrays as variables?
EDIT: in relation to Mat's Mug response
CLASS CHANGED:
Private pST As Variant
Public Property Get STContent(ByVal index As Long) As String
STContent = pST(index)
End Property
Public Property Let STContent(ByVal index As Long, ByVal value As String)
pST(index) = value
End Property
Private Sub Class_Initialize()
ReDim pST(0 To 2)
End Sub
CODE RUN TO TEST:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.STContent(0) = "test" '<--- Type mismatch here
Debug.Print foo.STContent(0)
End Sub
Your getter would need to return a String() array for the types to be consistent:
Public Property Get ST() As String()
However I wouldn't recommend exposing an array like this. First because assigning typed arrays is rather painful, second because the setter (Property Let) is actually cheating here:
Public Property Let ST([ByRef] value() As String)
Unless you specify ByVal explicitly, a parameter is always passed ByRef in VBA... except there's this quirk about Property Let - the RHS/value parameter is always passed ByVal at run-time.
And arrays can only ever be passed ByRef.
Therefore, a property that gets (or assigns, actually) a whole array doesn't make much sense.
A better way would be to encapsulate the array (I'd make it a Variant though), and expose its contents (not the array itself) through an indexed property:
Private internal As Variant 'String array
'...
Public Property Get Content(ByVal index As Long) As String
Content = internal(index)
End Property
Public Property Let Content(ByVal index As Long, ByVal value As String)
internal(index) = value
End Property
You have a lot of issues there.
First, your Property Get needs to return a String array. Second, your array needs to be dynamic, or you need to rewrite the whole thing so that you pass an index value to it, otherwise there is no way to indicate which value you are passing to the array. So, for example, using a dynamic array:
Private pST() As String
Public Property Get ST() As String()
ST = pST
End Property
Public Property Let ST(value() As String)
pST() = value()
End Property
and the calling code:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
Dim asData() As String
ReDim asData(0)
asData(0) = "test"
foo.ST = asData
Debug.Print foo.ST()(0)
End Sub
Unfortunately, I couldn't be sure form the original what the intent was.
It is getting late here but give it a try. In the module:
Option Explicit
Sub Test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.AddValueToSt "test", 1
Debug.Print foo.ST(1)
End Sub
In the Class:
Option Explicit
Private pST
Public Property Get ST() As Variant
ST = pST
End Property
Public Property Let ST(value As Variant)
pST = value
End Property
Public Function AddValueToSt(value As Variant, position As Long)
pST(position) = value
End Function
Private Sub Class_Initialize()
ReDim pST(2)
End Sub
This is my way to use the Factory Method Pattern. When I say "my way", for me this pattern is translated to "Whenever some OOP requires more than 5 minutes of thinking simply add a function."
I have a DataGrid which displays data from an Access database. Basically what I am trying to do is make it so that when the database is added to or updated then I want to show that in the Datagrid.
What I have so far is a timer that will update every 2 seconds:
Public Sub New()
_UserList = New List(Of Users)
showUsers()
Tmr.Interval = 2000
Tmr.Start()
End Sub
Private Sub TimerEventProcessor(myObject As Object, ByVal myEventArgs As EventArgs) Handles Tmr.Elapsed
showUsers()
OnPropertyChanged("SelectedCpuList")
OnPropertyChanged("UserList")
End Sub
This would normally work, but I am also doing checks on that data which involve looking at the selected row and allowing the user to delete that record. This is where it breaks, basically the selected item will get set every time a row is clicked on but the showUsers() method will set this value to an empty string again.
Public ReadOnly Property UserList() As List(Of Users)
Get
Return _UserList
End Get
End Property
Public Sub showUsers()
Dim SelCpuID As String = ""
If hasRemoved = True Then
If _SelectedCpuList.Count <= 1 Then
_SelectedCpuList.Clear()
OnPropertyChanged("SelectedCpuList")
OnPropertyChanged("UserList")
hasRemoved = False
Else
OnPropertyChanged("SelectedCpuList")
OnPropertyChanged("UserList")
hasRemoved = False
End If
End If
For Each c In _SelectedCpuList
If String.IsNullOrEmpty(SelCpuID) OrElse SelCpuID.Length = 0 Then
SelCpuID = c.MachineID
End If
Next
_selUserList = SelCpuID
_MachineID = SelCpuID
_UserList = BLL.getUsers()
OnPropertyChanged("SelectedCpuID")
OnPropertyChanged("machineID")
End Sub
Private _SelectedCpuList As New List(Of Users)
Public Property SelectedCpuList() As List(Of Users)
Get
Return _SelectedCpuList
End Get
Set(ByVal value As List(Of Users))
_SelectedCpuList = value
OnPropertyChanged("SelectedCpuList")
showUsers()
End Set
End Property
Private _SelectedCpuID As Users
Public Property SelectedCpuID() As Users
Get
Return _SelectedCpuID
End Get
Set(ByVal value As Users)
_SelectedCpuID = value
OnPropertyChanged("SelectedCpuID")
Dim temp As New List(Of Users)
temp.Add(_SelectedCpuID)
SelectedCpuList = temp
End Set
End Property
This will loop through everything in _SelectedCpuList (Selected row in data grid) and if the selected string is empty then it will set the selected string to the cpuID of the selected row.
The line SelCpuID = c.MachineID is giving me a Null Reference Exception which I believe may be to do with the constant attempts at updating the DataGrid.
So I think this is the wrong approach to make and there must be another way to update data when something is changed or added in the database? Other wise the user will have to hit a refresh button which could be a pain if they forget to do so.
I'm working on a program to parse a file name based on a drag drop, and process and remove a list of words that may be found in the file. I had the program working, but in a not so elegant manner, as well as a manner that would introduce issues later on in the program.
I'm trying create a list of a custom class or structure.
Here's what I have:
Public Class moviePath
Public currentPath As String
Public currentNameExt As String
Public currentName As String
Public currentExt As String
Public correctedName As String
Public correctYear As String
End Class
The issue is then when I attempt to create a usable variable based on this:
Dim workingList as New List(Of moviePath)
I'm left with no good way to correctly add data to the list using subs such as this:
Sub scanParent(ByVal sDir As String)
Dim f As String
Dim i As Integer = 0
Try
For Each f In Directory.GetFiles(sDir)
workingList(i).currentName = (Path.GetFileNameWithoutExtension(f))
workingList(i).currentNameExt = (Path.GetFileName(f))
workingList(i).currentPath = (Path.GetFullPath(f))
i += 1
Next
Catch excpt As System.Exception
MessageBox.Show("It didn't work " & excpt.ToString)
End Try
End Sub
Hopefully those tidbits make sense. scanParent sub is called passing the path to a folder as the argument (ie C\somefolder) and I intend to populate an array of sorts with information about files and folders. My reasoning is that I would like to be able to remove words from movie titles, in order use a opensource library (not sure if correct language) that parses IMDB to pull in movie info.
The main thing that I need is for each item in the class moviePath to be addressable and tied to each other item at that position in the list.
EDIT: ie. moviePath(0).currentPath would be in reference to the same file moviePath(0).currentName
For Each f In Directory.GetFiles(sDir)
dim info as new moviePath
info.currentName = (Path.GetFileNameWithoutExtension(f))
info.currentNameExt = (Path.GetFileName(f))
info.currentPath = (Path.GetFullPath(f))
workingList.add(info)
Next
You should be using the List(T).Add method for this.
Sub scanParent(ByVal sDir As String)
Dim f As String
Try
For Each f In Directory.GetFiles(sDir)
Dim newPath As New moviePath()
newPath.currentName = (Path.GetFileNameWithoutExtension(f))
newPath.currentNameExt = (Path.GetFileName(f))
newPath.currentPath = (Path.GetFullPath(f))
workingList.Add(newPath)
Next
Catch excpt As System.Exception
MessageBox.Show("It didn't work " & excpt.ToString)
End Try
End Sub
I agree with Plutonix. In addition to the fix by Bradley, also pass the FileName to your movePath class like this:
Public Class moviePath
Public Sub New(ByVal FullFilePath As String)
Me.currentPath = FullFilePath
Me.currentName = Path.GetFileNameWithoutExtension(FullFilePath)
Me.currentNameExt = Path.GetFileName(FullFilePath)
End Sub
Public currentPath As String
Public currentNameExt As String
Public currentName As String
Public currentExt As String
Public correctedName As String
Public correctYear As String
End Class
Now your loop becomes simply:
For Each f In Directory.GetFiles(sDir)
workingList.add(New moviePath(f))
Next
I have a Class ABC. And i want to write two properties for
it. One i have already mentioned in the code. The other one will be a single dimensional array.
Public Class ABC
Private m_Type As String
Private SomeArray........need to write a property for array which will be of type `int`
Public Property Type() As String
Get
Return m_Type
End Get
Set(ByVal value As String)
m_Type = value
End Set
End Property
End Class
I am not sure how to define a property for array which can be used in a List(Of ABC). The property for array can be a read only array as i will be
hard coding the data for it.
So basically when i do this,
Dim SomeList As New List(Of ABC)
And inside a for loop i need something like this,
SomeList.Item(index).SomeArray......this will give me all the items inside the array
You can declare an array property the same way as you declare a different property type:
Public Class ABC
Private _Type As String
Private _SomeArray As Int32()
Public Property SomeArray As Int32()
Get
Return _SomeArray
End Get
Set(ByVal value As Int32())
_SomeArray = value
End Set
End Property
Public Property Type() As String
Get
Return _Type
End Get
Set(ByVal value As String)
_Type = value
End Set
End Property
End Class
for example, if you want to loop all Integers in one array of the list:
Dim index As Int32 = 0
Dim someList As New List(Of ABC)
For Each i As Int32 In someList(index).SomeArray
Next
If you're not going to be doing anything special in the Gets and Sets, you could simplify your code a little, as in the following (which initializes the read only array to contain the numbers 1, 2, 3 and 4):
Public Class ABC
Public Property Type As String
Public ReadOnly Property SomeArray As Integer() = {1,2,3,4}
End Class
Upon selecting a Question ID in the combo box the relating question should then appear in the text box. I am unsure how to get this to work though. I receive an error "Value of type......cannot be converted to string" on retrieveQuestion(). Any help is appreciated, thankyou.
Private Sub cmbQuestion_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbQuestion.SelectedIndexChanged
txtExistingQuestion.Text = retrieveQuestion() 'Add question, relevant to Question ID, to text box, DO I NEED .ToString?????????????????
loaded = True
End Sub
Public Function retrieveQuestion() As List(Of Question) 'Retrieves selected question into text box
Dim typeList As New List(Of Question)
Dim Str As String = "SELECT Question_ID, Question_Text FROM Question WHERE Question_ID =" & cmbQuestion.SelectedValue
Try
Using conn As New SqlClient.SqlConnection(DBConnection)
conn.Open()
Using cmdQuery As New SqlClient.SqlCommand(Str, conn)
Using drResult As SqlClient.SqlDataReader = cmdQuery.ExecuteReader()
While drResult.Read
typeList.Add(New Question(drResult("Question_ID"), drResult("Question_Text")))
End While
End Using 'Automatically closes connection
End Using
End Using
Catch ex As Exception
MsgBox("Question List Exception: " & ex.Message & vbNewLine & Str)
End Try
Return typeList
End Function
Public Class Question 'defining one club within class
Public Sub New(ByVal questionID As Integer, ByVal questionText As String)
mQuestionID = questionID 'm is for member of the class
mQuestionText = questionText
End Sub
Private mQuestionID As String = ""
Private mQuestionText As String = ""
Public Property QuestionID() As String
Get
Return mQuestionID
End Get
Set(ByVal value As String)
mQuestionID = value
End Set
End Property
Public Property QuestionText() As String
Get
Return mQuestionText
End Get
Set(ByVal value As String)
mQuestionText = value
End Set
End Property
End Class
Your issue is this line:
mQuestionID = questionID
In your class you have defined this:
Private mQuestionID As String = ""
But in your constructor, you are saying that questionID should be an Integer, like this:
Public Sub New(ByVal questionID As Integer, ByVal questionText As String)
You need to change your backing variable in your class (mQuestionID) to be an Integer, like this:
Private mQuestionID As Integer
This will also necessitate a change to the property syntax for QuestionID, like this:
Public Property QuestionID() As Integer
Get
Return mQuestionID
End Get
Set(ByVal value As Integer)
mQuestionID = value
End Set
End Property
Your error is originated by the return value of retrieveQuestion declared as a List(Of Question) but then you try to set the text property of a TextBox (and there is no way to convert automatically a List(Of Question) to a string)
So you could write something like this to extract the text of the first question in the list
Dim qList = retrieveQuestion()
if qList.Count > 0 then
txtExistingQuestion.Text = qList(0).QuestionText
loaded = True
End If
Of course, if your query returns zero or just one question, then there is no need to return a List(Of Question) and you can change the retrieveQuestion method to return just a Question or Nothing
Public Function retrieveQuestion() As Question
Dim questionResult As Question = Nothing
......
Using drResult As SqlClient.SqlDataReader = cmdQuery.ExecuteReader()
if drResult.Read() then
questionResult = New Question(drResult("Question_ID"), _
drResult("Question_Text")))
End if
End Using
....
return questionResult
End Function
Dim question = retrieveQuestion()
if question IsNot Nothing then
txtExistingQuestion.Text = question.QuestionText
loaded = True
End If
However, all the comments about string and integer conversion happening automatically on your code are really an alarm bell. You should strive to avoid this kind of conversion because they render your code weak and prone to misterious errors. Switch to Option Strinct On on your project properties and prepare yourself to a lot of conversion fixing.