Vb console questions how to - vb.net

Right I want to know how to, if possible to use code that has already been read or an effective way for doing it.
I want to be able to use the location variable without having to write it out hundreds of times.
Hopefully you understand what im talking about. I want to be able to leave the shop and the come back to this console.writeline("where would you like to go") part.
Console.WriteLine("where would you like to go")
Console.WriteLine("1 - The shop")
location = Console.ReadLine()
Loop Until location = "1"
Console.WriteLine("")
Console.WriteLine("")
Console.WriteLine("")
Console.WriteLine("***********************************The Shop***********************************")
Console.ReadLine()
Console.WriteLine("")
Console.writeline("Shopkeeper: how can I help you")

I would advise you to try a more structured approach. Use a new class called Location that contains information about each location (example has a name and a list of possible destinations). This can of course be further advanced with possible interactions and such things.
Public Class Location
Public Property Name As String
Public Property Destinations As List(Of String)
Public Sub New(Name As String, Destinations As String())
Me.Name = Name
Me.Destinations = New List(Of String)
Me.Destinations.AddRange(Destinations)
End Sub
End Class
You first make a list of locations in your game. I made three, the street, the shop and the shop's back room (mysterious!).
On each iterations you display a list with the locations from the objects you made and let the user choose one. You then change the location based on the name.
That way you can easily add locations and interconnections.
You don't really want to hardcode every step the user can take.
Module Module1
Sub Main()
'Create locations
Dim Locations As New List(Of Location)
Locations.Add(New Location("Shop", {"Street", "Back Room"}))
Locations.Add(New Location("Street", {"Shop"}))
Locations.Add(New Location("Back Room", {"Shop"}))
'Define a starting location
Dim CurrentLocation As String = "Street"
Do
Console.WriteLine("You are at: " & CurrentLocation)
Console.WriteLine("Destinations: ")
'Bit of Linq to select the location by name from your defined locations
Dim ThisLocation As Location = (From l As Location In Locations Where l.Name = CurrentLocation Select l).First
'Display the possible destinations from here
For i = 0 To ThisLocation.Destinations.Count - 1
Console.WriteLine(String.Format("-{0}- {1}", (i + 1).ToString, ThisLocation.Destinations(i)))
Next
'Read user input for a the destination he wants to travel to
Dim NewLocation As Integer = -1
Do
Console.Write(" Go to: ")
Integer.TryParse(Console.ReadLine, NewLocation)
Loop Until NewLocation >= 1 AndAlso NewLocation <= ThisLocation.Destinations.Count
'Change the current location
CurrentLocation = ThisLocation.Destinations(NewLocation - 1)
Loop
End Sub
End Module

Related

Skip block of text from adding to dictionary vb.net

I want to know if there is a way to read a text file that lets say has content like so:
Store - 001P
Owner - Greg
Price - 45000
Employees - 30
Store - 002
Owner- Jen
Price - 34400
Now lets say I only want to work with the store information in the block where the store number contains a P. Is there a way to read the text file to check for the P after the delimiter, and then skip to the next instance of "store" in the text file? I tried to find which function is best as in different languages you can GoTo function, but I cannot find anything on this.
This is a snippet of my current code:
Dim columnV As New Dictionary(Of String, Integer)
Dim descriptionV As String
Dim quantityV As Integer
For Each totalLine As String In MyData
descriptionV = Split(totalLine, "-")(0)
quantityV = Split(totalLine, "-")(1)
If columnV.ContainsKey(descriptionV) Then
columnV(descriptionV) = colSums(descriptionV) + quantityV
Else
columnV.Add(descriptionV, quantityV)
End If
'Next
Ok, if I read this correct, you only want to worry about and process stores that end in a "P". Did I get that right?
and your data is like this then:
Store - 001P \n Owner - Greg \n Price - 45000 \n Employees - 30 \n
Store - 002\n Owner- Jen \n Price - 34400 \n
So in code we could go:
dim store as string
dim Owner as string
dim Price as decimal
dim employees as integer
' your code to read the data
now we have the process loop
For Each totalLine As String In MyData
store = trim(split(split(totalLine,"\n)(0),"-")(1))
Owner = trim(split(split(totalLine,"\n)(1),"-")(1))
Price = trim(split(split(totalLine,"\n")(3),"-")(1))
Employees = trim(split(split(totalLine,"\n")(4),"-")(1))
if strings.right(store,1) = "P" then
' our process code
If columnV.ContainsKey(store) Then
end if
Next
So you can use Strings.Right(some text,1) to get the right most character. You simply then have a if/then block around that code, and thus you skip anything that does not have a store with "P" as the last letter. The above is air code, but the simple concept here is to first:
Split out the line into the correct parts.
Check if store ends in "P" with the above if/then, and thus only stores ending in P will be processed.
However, your sample code and the variable names used really does not make a lot of sense.
It appears as if a record can be represented across multiple lines, but not a defined number of multiple lines (e.g. 001P is over 4 lines but 002 is over 3 lines).
It also appears as if the line represents the data in a {property} - {value} format.
The first thing that I would do is create a class to represent your record.
The second thing would be to get every line from your text file and iterate over them.
The third thing would be take the incoming information and convert it to your custom class which would be added to a List.
The last thing would be to then filter the List where Stores do not contain the letter "P".
Here is the code, in action:
Imports System
Imports System.Collections.Generic
Imports System.Linq
Public Module Module1
Public Sub Main()
IO.File.WriteAllLines("test.txt", {
"Store - 001P",
"Owner - Greg",
"Price - 45000",
"Employees - 30",
"Store - 002",
"Owner - Jen",
"Price - 34400"
})
Dim lines() As String = IO.File.ReadAllLines("test.txt")
Dim stores As List(Of Store) = ConvertLinesToStores(lines)
Dim storesWithP() As Store = stores.Where(Function(s) s.StoreId.Contains("P")).ToArray()
Console.WriteLine("Stores with P: ")
Console.WriteLine(String.Join(Environment.NewLine, storesWithP.Select(Function(s) s.StoreId).ToArray()))
End Sub
Private Function ConvertLinesToStores(ByVal lines() As String) As List(Of Store)
Dim stores As New List(Of Store)
Dim item As Store
For Each line As String In lines
Dim parts() As String = line.Split(" - ")
If (lines.Length < 3) Then
Continue For
End If
Dim propertyName As String = parts(0)
Dim propertyValue As String = parts(2)
Dim employeeCount As Integer
If (propertyName = "Store") Then
If (item IsNot Nothing) Then
stores.Add(item)
End If
item = New Store() With {.StoreId = propertyValue}
ElseIf (propertyName = "Owner") Then
item.Owner = propertyValue
ElseIf (propertyName = "Price") Then
item.Price = propertyValue
ElseIf (propertyName = "Employees" AndAlso Integer.TryParse(propertyValue, employeeCount)) Then
item.EmployeeCount = employeeCount
End If
Next
If (item IsNot Nothing) Then
stores.Add(item)
End If
Return stores
End Function
End Module
Public Class Store
Public Property StoreId As String
Public Property Owner As String
Public Property Price As Integer
Public Property EmployeeCount As Integer
End Class
Fiddle: Live Demo
Assuming your text file has a consistent pattern the following will give you a list of your stores with all the properties.
My Stores.txt looks like this...
Store - 001P
Owner - Greg
Price - 45000
Employees - 30
Store - 002
Owner- Jen
Price - 34400
Employees - 20
Store - 03P
Owner - Mary
Price - 50000
Employees - 22
Store - 04P
Owner - Bill
Price - 42000
Employees - 90
I created a simple class to hold the store data.
Public Class Store
Public Property ID As String
Public Property Owner As String
Public Property Price As Decimal
Public Property Employees As Integer
End Class
First I read the file getting an array of lines. I loop through the lines of the file skipping ahead by 5 on each iteration (Step 5).This should hit the Store line (Store appears every 5 lines).
If it contains a P then I create a new Store and set it properties by moving down one line (the i + 1 etc.). After the properties are set, I add the Store to the list.
Now you have a List(Of Store) containing only the stores who's Id contains a P. You can access the items by index or in a For Each loop and have all the properties available.
Private StoreList As New List(Of Store)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines = File.ReadAllLines("C:\Users\maryo\Desktop\Stores.txt")
For i = 0 To lines.Length - 4 Step 5
Dim ID = lines(i).Split("-"c)(1).Trim
If ID.Contains("P") Then
Dim st As New Store
st.ID = ID
st.Owner = lines(i + 1).Split("-"c)(1).Trim
st.Price = CDec(lines(i + 2).Split("-"c)(1).Trim)
st.Employees = CInt(lines(i + 3).Split("-"c)(1).Trim)
StoreList.Add(st)
End If
Next
'Just to check if my list contains what I expected.
DataGridView1.DataSource = StoreList
End Sub

Is it possible for a picture box to detect colour in another picture box and avoid it?

I am currently attempting to make a visual route planner interface for a local town.
The GUI is a map lacking in detail simply showing a green background with grey lines for the roads.
Is it possible for another picture box representing a vehicle to avoid and be unable to access the green coloured areas of the Map Picture box?
How can I make the car picture box follow certain routes along the map picture box that can be worked out through calculations?
We'll do this in a couple steps:
Build the map from the data.
Implement a flexible pathfinding algorithm.
Draw a human-friendly version of the map.
Wrap up with user interactions.
I'll enrich this answer as you progress so it stays relevant.
1
First thing, we'll manipulate data. A road map is basically a network of points (or nodes) linked by lines (which I'll call vertex).
The points have coordinates (so we can draw them later), and sometimes other values, like a name. They are every start and end of a road, and sometimes in-between. To keep things simple, the user will only be able to start and end on points.
Vertex have length and sometimes stuff like "difficulty", "max speed", etc. These stats will determinate which road is the most optimized for the user's trip. We can also make sure that the algorithm doesn't consider a vertex when the user doesn't want to go this way, or force him to go through a specific vertex if we choose so.
You'll find that I included a sample map by setting it up in the map's constructor. I included approximative coordinates and distances. You can change it any way you like. Here what the data represents:
2
I'm using the A* (read A STAR) algorithm here. You mentioned Dijkstra's algorithm sooner, which is nice, but for this purpose I'll stick to A*.
There are differences between these two methods. If you wikipedia them, you'll find these two images which, I think, show really well the main difference between the two:
Dijkstra's algorithm:
A* algorithm:
As you can see by yourself, both algorithm are doing a fine job.
I commented the code, but You'll probably have a ton of questions about all these things. I'll hang around to answer them.
To manipulate this algorithm, you have to know this:
the difficulty value of a vertex makes it seem longer to the algorithm. It's not necessary (which is why I put it to 1 everywhere), but if you want to compare a mountain road to a speedway or a road with a 30 km/h speed limit to another one where you can speed at 100 km/h, you can tweak this value.
the x and y coordinates of the nodes aren't very important in themselves, but the A* algorithm uses them to get this "I'm going toward my goal" effect you just saw in the image. Approximatives values are fine, as long as there are values that make some sense in there. You could calculate the H value otherwise, but as this is cartography I though it made sense.
a vertex MUST ALWAYS be connected to a starting point and an end point. Which is which have no meaning, as long as there are two of them (or the same point twice, but that would lead to the place where it started without any gain whatsoever).
a point may have any number of vertex.
you could make some points "impossible to pass", but I didn't code it that way. You can pump up the difficulty to an insane amount to get a somewhat similar result, except that if there are no other way the algorithm will eventually use the difficult path anyway.
if the end node has no connection to the network of the starting node, the algorithm will try everything then abandon and let you know that there is no path to the end point.
use the TestMyMap() sub to try some pathfinding. Calculate it by yourself to compare. Change the end point and the starting point for something else. Go wild!
The Code
#Region " Mapping "
Public Class MapPoint
Private _vertexList As New List(Of MapVertex) 'one point can have as many "roads" as you want
Private _xCoord As Decimal 'for now the coordinates are meaningless, but at some point we might want to use them to actually paint the map
Private _yCoord As Decimal
Private _name As String 'just a useful label
Public Parent As MapVertex = Nothing 'useful for backtracking at the end (and get an itinary)
'f is the total "cost" of the the node being analyzed (f = g + h) while doing pathfinding
'g is the distance between the node being analyzed and the starting point while doing pathfinding
'those values serve no other purpose
'h is the estimated minimal distance between the two points while doing pathfinding
'in the Sub 'CalculateH' I'm using the points coordinates and simple trigonometry to estimate h
'technically you can skip the square root part, but I decided against it. There are no dealmaking advantages to my decision.
'it's better to underestimate the minimal distance, that's why a theoretical straight line is a good choice
Public f As Decimal = 0
Public g As Decimal = 0
Public h As Decimal = 0
Public ReadOnly Property VertexList As List(Of MapVertex)
Get
Return _vertexList
End Get
End Property
Public ReadOnly Property X As Decimal
Get
Return _xCoord
End Get
End Property
Public ReadOnly Property Y As Decimal
Get
Return _yCoord
End Get
End Property
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public Sub New(name As String, xx As Decimal, yy As Decimal, ParamArray vertex() As MapVertex)
_name = name
_xCoord = xx
_yCoord = yy
For Each v As MapVertex In vertex
_vertexList.Add(v)
Next
End Sub
Public Sub AddVertex(vertex As MapVertex)
_vertexList.Add(vertex)
End Sub
Public Sub CalculateH(startingPoint As MapPoint, endPoint As MapPoint)
h = Convert.ToDecimal(Math.Sqrt(Math.Pow((startingPoint.X - endPoint.X), 2) + Math.Pow((startingPoint.Y - endPoint.Y), 2)))
End Sub
Public Sub UpdateFandG(currentNodeG As Decimal, distance As Decimal)
g = currentNodeG + distance
f = g + h
End Sub
Public Sub ResetPathfindingValues()
f = 0
g = 0
h = 0
Parent = Nothing
For Each v As MapVertex In _vertexList
v.ResetPathfindingValues()
Next
End Sub
End Class
Public Class MapVertex
Private _name As String 'just a useful label
Private _length As Decimal 'length of the road. If you have straight roads we can use simple math to get the distances, but curvy roads have their own length, and I'll assume that your roads will be anything
Private _difficulty As Decimal 'if you want to make some roads faster than others, we can use a variable like this one. It could be something else, like "maxSpeed", but for a prototype "difficulty" will do fine
'I suggest making the difficulty a multiplier. It'll be easier to use that way (so a road twice faster would be a '0.5' and a road twice harder to use would be a '2.0')
Public Parent As MapPoint = Nothing 'useful for backtracking at the end (and get an itinary)
'start and end has no meaning here, as both are end points for the line. The important part is that they refer to existing points
'a vertex must ALWAYS be linked to two points (or it makes no sense, you cannot have a line with only one end unless you go full moebius and we're not using enough dimensions for this to make sense
'if you feel like it, you can have a vertex looping from one point and going back to it, but it'll serve no purpose and will never be actually used except by the pathfinding algorithm (which will note it as a bad move every time)
Private _startPoint As MapPoint
Private _endPoint As MapPoint
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
'you can play around with difficulty if you like, it'll change which path the algorithm thinks is the better
Public ReadOnly Property AdjustedLength As Decimal
Get
Return _length * _difficulty
End Get
End Property
Public Sub New(name As String, startPoint As MapPoint, endPoint As MapPoint, length As Decimal, difficulty As Decimal)
_name = name
_startPoint = startPoint
_endPoint = endPoint
_length = length
_difficulty = difficulty
'automatically adding this vertex to it's points on creation:
_startPoint.AddVertex(Me)
_endPoint.AddVertex(Me)
End Sub
'this function is so we can get the "other side" of a path from it's start
Public Function GetOtherNode(currentNode As MapPoint) As MapPoint
If _startPoint Is currentNode Then
Return _endPoint
Else
Return _startPoint
End If
End Function
Public Sub ResetPathfindingValues()
Parent = Nothing
End Sub
End Class
Public Class Map
'the Map object is a collection of points.
'those points are linked by vertex
'it could be different depending on what's your purpose
Private _points As New List(Of MapPoint)
Public Function GetPoint(name As String) As MapPoint
For Each p As MapPoint In _points
If p.Name = name Then
Return p
End If
Next
Return Nothing
End Function
Public Sub New()
'You can use this part to build a simple map with a handful of points. For the demonstration that's how we'll work, but later on you can design a mean to load maps from a specific source if you want
'Here's one I threw on the screen at random. If you have one you like better, send me a pastebin and I'll use it instead
'First I create the points:
Dim oldBarn As MapPoint = New MapPoint("Old Barn", 0, 0)
Dim home As MapPoint = New MapPoint("Home", 0, 12)
Dim forest As MapPoint = New MapPoint("Forest", 0, 21)
Dim creepyDeadEnd As MapPoint = New MapPoint("Creepy Dead End", 0, 26)
Dim groceries As MapPoint = New MapPoint("Groceries", 11, 8)
Dim girlfriendsPlace As MapPoint = New MapPoint("Girlfriend's Place", 20, 8)
Dim friendsHome As MapPoint = New MapPoint("Friend's Home", 5, 13)
Dim bar As MapPoint = New MapPoint("The Foo's Bar", 32, 14) 'hehehe
'Second I create the roads between those points (as long as 2 points exist I could create the road, I just decided I would be systematic)
Dim smallRoad As MapVertex = New MapVertex("Small Road", oldBarn, home, 12, 1)
Dim oakStreet As MapVertex = New MapVertex("Oak Street", home, forest, 9, 1)
Dim pathway As MapVertex = New MapVertex("Pathway", forest, creepyDeadEnd, 5, 1)
Dim oldRoad As MapVertex = New MapVertex("Old Road", oldBarn, friendsHome, 17, 1)
Dim arlingtonStreet As MapVertex = New MapVertex("Arlington Street", home, groceries, 7, 1)
Dim fourthStreet As MapVertex = New MapVertex("4th Street", home, girlfriendsPlace, 12, 1)
Dim placeLittlefinger As MapVertex = New MapVertex("Place Littlefinger", groceries, girlfriendsPlace, 9, 1)
Dim cedarCreek As MapVertex = New MapVertex("Cedar Creek", forest, bar, 19, 1)
Dim alley As MapVertex = New MapVertex("Alley", friendsHome, groceries, 7, 1)
Dim mainStreet As MapVertex = New MapVertex("Main Street", groceries, bar, 22, 1)
Dim durnhamRoad As MapVertex = New MapVertex("Durnham Road", friendsHome, bar, 27, 1)
Dim secretRoad As MapVertex = New MapVertex("Secret Road", oldBarn, bar, 61, 1)
'Adding the points to the Map
_points.AddRange({oldBarn, home, forest, creepyDeadEnd, groceries, girlfriendsPlace, friendsHome, bar})
End Sub
'This is an implementation of the A* algorithm, which is a very popular pathfinding algorithm for simple grids/node networks
'You could use Dijkstra's algorithm if you like it better or are a Sapkowsky's fan, but I think A* will do a great job here
Public Function FindTheShortestPath(startingPoint As MapPoint, endPoint As MapPoint) As String
Dim openList As New List(Of MapPoint) 'nodes that are going to be analyzed soon
Dim closedList As New List(Of MapPoint) 'nodes that have been analyzed
'we always start the analysis... from the starting point of course!
openList.Add(startingPoint)
startingPoint.CalculateH(startingPoint, endPoint)
'as long as we haven't found the path to the end point, the algorithm will continue looking
'there are 2 ways to exit this function:
' #1 is finding the endPoint
' #2 is having nowhere left to go and still not finding the end point (which means that it's impossible)
While (openList.Count > 0)
'look for the lowest f in the openList
'this is our current node for the analysis
Dim currentNode As MapPoint = Nothing
For Each p As MapPoint In openList
If currentNode Is Nothing OrElse p.f < currentNode.f Then
currentNode = p
End If
Next
'remove the currentNode from the open list (it's being analyzed) and add to the closedList (no need to come back)
openList.Remove(currentNode)
closedList.Add(currentNode)
'check if we've reached the end node
If currentNode Is endPoint Then
'yay!
'now let's backtrack to get an itinary:
Dim path As String = BackTrack(endPoint)
ResetAllPathfindingVariables()
Return path
End If
'finding which nodes are connected to the Current node
'then analyzing it
For Each vertex As MapVertex In currentNode.VertexList
Dim nextNode As MapPoint = vertex.GetOtherNode(currentNode)
'only work on a node if it's out of the closedList
If Not closedList.Contains(nextNode) Then
'I'm tracking parents to make an itinary when this is finished
nextNode.CalculateH(currentNode, endPoint)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
'if it's not yet on the openList, now's time to add it there!
'(I know that a negative check with a 'Else' clause is stupid, but it's easier to read in this context)
If Not openList.Contains(nextNode) Then
openList.Add(nextNode)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
Else
'if this is a known node but we found a faster path to reach it, update it's parent
If currentNode.g + vertex.AdjustedLength < nextNode.g Then
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
End If
End If
End If
Next
End While
ResetAllPathfindingVariables()
Return "No path was found."
End Function
Private Sub ResetAllPathfindingVariables()
For Each p As MapPoint In _points
p.ResetPathfindingValues()
Next
End Sub
'recursive function to show the path found by the algorithm
Private Function BackTrack(location As Object, Optional path As String = "") As String
If path <> "" Then path = " => " & path
Select Case True
Case TypeOf location Is MapPoint
Dim currentPoint As MapPoint = DirectCast(location, MapPoint)
path = currentPoint.Name & path
If currentPoint.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentPoint.Parent, path)
End If
Case TypeOf location Is MapVertex
Dim currentVertex As MapVertex = DirectCast(location, MapVertex)
path = currentVertex.Name & path
If currentVertex.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentVertex.Parent, path)
End If
End Select
Return ""
End Function
End Class
Private Sub TestMyMap()
_map = New Map()
Dim path As String = _map.FindTheShortestPath(_map.GetPoint("Home"), _map.GetPoint("The Foo's Bar"))
Console.WriteLine(path)
End Sub
#End Region
Of course I'll be there to help you understand this part. It's heavy, I know. It's still a lot of fun, especially once it's finished and you get to use it!

Get extended file information details

How can one obtain the details of a windows file using VB.net?
The type of details I mean are those found when I right click on a file, say an MS word doc, then click "Properties" and select the "Details" tab.
I know some can be obtained via FileInfo, but not all, such as "Tags" for example.
Thanks
For that stuff you need to use Shell32. From the COM tab, find and add Microsoft Shell Controls and Automation. Here is code to create a list of property-values for a given file:
' class to hold the goodies
Friend Class ShellInfo
Public Property Name As String
Public Property Value As String
Public Sub New(n As String, v As String)
Name = n
Value = v
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Then a function to fill it up
Private Function GetXtdShellInfo(filepath As String) As List(Of ShellInfo)
' ToDo: add error checking, maybe Try/Catch and
' surely check if the file exists before trying
Dim xtd As New List(Of ShellInfo)
Dim shell As New Shell32.Shell
Dim shFolder As Shell32.Folder
shFolder = shell.NameSpace(Path.GetDirectoryName(filepath))
' its com so iterate to find what we want -
' or modify to return a dictionary of lists for all the items
Dim key As String
For Each s In shFolder.Items
' look for the one we are after
If shfolder.GetDetailsOf(s, 0).ToLowerInvariant = Path.GetFileName(file).ToLowerInvariant Then
Dim ndx As Int32 = 0
key = shfolder.GetDetailsOf(shfolder.Items, ndx)
' there are a varying number of entries depending on the OS
' 34 min, W7=290, W8=309 with some blanks
' this should get up to 310 non blank elements
Do Until String.IsNullOrEmpty(key) AndAlso ndx > 310
If String.IsNullOrEmpty(key) = False Then
xtd.Add(New ShellInfo(key,
shfolder.GetDetailsOf(s, ndx)))
End If
ndx += 1
key = shfolder.GetDetailsOf(shfolder.Items, ndx)
Loop
' we got what we came for
Exit For
End If
Next
Return xtd
End Function
Using it is simple:
Dim xtd As List(Of ShellInfo) = GetXtdShellInfo("C:\Temp\Capri.jpg")
For Each s As ShellInfo In xtd
Console.WriteLine("{0}: {1}", s.Name, s.Value)
Next
The return should be a list of ShellInfo items where the Name is the property name such as Name, BitRate, Album and the associated Value will be that returned by Shell32. e.g
Name: Capri.jpg
Size: 15.2 KB
Item type: Image File
Date modified: 7/20/2014 12:19 PM
Date created: 7/20/2014 12:17 PM
Date accessed: 7/20/2014 12:17 PM
(etc)
The actual number returned will vary depending on the OS ver
As noted in the comment Microsoft Shell Controls and Automation is renamed as Microsoft Shell Folder View Router (in Windows 8.1).
Also, the first 35 properties are fairly well known and more common, but with Win7 there are about 291. Under Windows 8, the max is 309 with some blank spots and deep into the list some property indices are changed.
See this answer related question How to read the bit rate information from a .mov video file header
Dim shellAppType = Type.GetTypeFromProgID("Shell.Application")
Dim shellApp = Activator.CreateInstance(shellAppType)
Dim folder = shellApp.NameSpace("c:\users\frank")
Dim folderitem = folder.parsename("yourfile.jpg")
Dim value = folder.GetDetailsOf(folderitem, 24) 'eg. 24 retrieves File Comments.
Just use something like :
Dim MyFileInfos as System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(PathToYourFile)
Then get infos using MyFileInfo.* (whatever you need, use IntelliSense).
Have a nice day

Adding a variable to a listBox in VB.net Windows Form

I am making a dvd database system in windows form and trying to display the dvd's entered by a user. Then display the Title, Director and Genre in 3 separate listBoxes.
When the user enters the information through 3 separate text boxes, the information is stored in a structure I made called TDvd. This means I can call for example dvd.Title or dvd.Director. I also use the variable index to add this information to an array I made called Dvd(100) (just a random number I used to test).
Here is the code I currently have for adding the items to the ListBox:
For i = 1 To noOfAddedDvds
lstTitle.Items.Add(dvd(i).Title)
lstDirector.Items.Add(dvd(i).Director)
lstGenre.Items.Add(dvd(i).Genre)
Next
The variable NoOfDvdsAdded is just a way of keeping track of the number of dvd's the user has already entered.
I run this and enter the Title, Director and Genre, but when I try and display this information across the 3 listboxes, I get the error:
An unhandled exception of type 'System.ArgumentNullException' occurred in System.Windows.Forms.dll
Public Class Form1
Structure TDvd
Dim Title As String
Dim Director As String
Dim Genre As String
End Structure
Dim dvd(100) As TDvd
Dim index As Integer = 0
Dim noOfAddedDvds As Integer
Private Sub btnAddToDatabase_Click(sender As Object, e As EventArgs) Handles btnAddToDatabase.Click
If txtDirector.Text <> "" Or txtGenre.Text <> "" Or txtTitle.Text <> "" Then
txtTitle.Text = dvd(index).Title
txtDirector.Text = dvd(index).Director
txtGenre.Text = dvd(index).Genre
index += 1
noOfAddedDvds += 1
End If
End Sub
Private Sub btnDisplayDatabase_Click(sender As Object, e As EventArgs) Handles btnDisplayDatabase.Click
Dim i As Integer
For i = 0 To noOfAddedDvds
MessageBox.Show(index & ", " & i)
lstTitle.Items.Add(dvd(i).Title)
lstDirector.Items.Add(dvd(i).Director)
lstGenre.Items.Add(dvd(i).Genre)
MessageBox.Show(index & ", " & i)
Next
End Sub
End Class
According to the documentation, an ArgumentNullException is thrown by the Add() method if the argument passed to it is null. (Or Nothing in VB.) So one of these is Nothing at runtime:
dvd(i).Title
dvd(i).Director
dvd(i).Genre
You'll have to debug to determine which. It would seem that the error is because you're starting your iteration at 1 instead of 0, I would think it should be:
For i = 0 To noOfAddedDvds - 1
So when you get to the index of noOfAddedDvds in your collection, that element will be an uninitialized struct with Nothing strings.
You'll definitely want to fix the iteration (indexes start at 0). Additionally, you may also benefit from initializing the String properties in your struct to String.Empty internally. Depends on whether you want similar errors to manifest as an exception or as an empty record. Sometimes the latter makes the problem more obvious since at runtime you'd see that your output started on the second record.
Just a few pointers...
The Items collection on the ListBox is actually 0 indexed, by which I mean that instead of going "1,2,3", it actually goes (0,1,2).
That's what your problem is.
Hint - think about perhaps using a List instead of an array as well... (for dvd)
Your thing cries out for being rewritten in OO form:
Friend DVDGenres
Undefined
Comedy
Action
Adventure
Sci-Fi
End Enum
Friend Class DVD
Public Property Title As String
Public Property Director As String
Public Property Genre As DVDGenres
Public Sub New
Title = ""
Director = ""
Genre = DVDGenres.Undefined
' other stuff too
End Sub
Public Overrides Function ToString As String
Return Title
End Sub
End Class
Now something to store them in. Arrays went out with Rubik's Cubes, so a List:
Private myDVDs As New List(of DVD)
A list and a class can do what arrays and structures can without the headaches. Add a DVD:
Dim d As New DVD
d.Name = TextBoxName.Text
d.Director = TextBoxDir.Text
d.Genre = comboboxGenre.SelectedItem
' add to the container:
myDVDs.Add(d)
Display all the DVDs in a ListBox to pick from:
AllDVDsLB.DataSource = myDVDs
AllDVDsLB.DisplayMember = "Title"
This will set your list as the datasource for the listbox. Whatever is in the List is automatically displayed without copying data into the Items collection. Then, say from selectedindex changed event, display the selected item details to some labels:
Label1.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Title
Label2.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Director
Label3.Text = Ctype(AllDVDsLB.SelectedItem, DVD).Genre.ToString
Iterate to do something like what is in the Question:
For Each d As DVD in myDVDs ' CANT run out of data
lstTitle.Items.Add(d.Title)
lstDirector.Items.Add(d.Director)
lstGenre.Items.Add(d.Genre.ToString)
Next
Or iterate and reference with an Int32:
For n As Integer = 0 To myDVDs.Count - 1
lstTitle.Items.Add(myDVDs(n).Title)
' etc
Next n
HTH

How To Read From Text File & Store Data So To Modify At A Later Time

What I am trying to do may be better for use with SQL Server but I have seen many applications in the past that simply work on text files and I am wanting to try to imitate the same behaviour that those applications follow.
I have a list of URL's in a text file. This is simple enough to open and read line by line, but how can I store additional data from the file and query the data?
E.g.
Text File:
http://link1.com/ - 0
http://link2.com/ - 0
http://link3.com/ - 1
http://link4.com/ - 0
http://link5.com/ - 1
Then I will read the data with:
Private Sub ButtonX2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonX2.Click
OpenFileDialog1.Filter = "*txt Text Files|*.txt"
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
Dim AllText As String = My.Computer.FileSystem.ReadAllText(OpenFileDialog1.FileName)
Dim Lines() = Split(AllText, vbCrLf)
Dim list = New List(Of Test)
Dim URLsLoaded As Integer = 0
For i = 0 To UBound(Lines)
If Lines(i) = "" Then Continue For
Dim URLInfo As String() = Split(Lines(i), " - ")
If URLInfo.Count < 6 Then Continue For
list.Add(New Test(URLInfo(0), URLInfo(1)))
URLsLoaded += 1
Next
DataGridViewX1.DataSource = list
LabelX5.Text = URLsLoaded.ToString()
End If
End Sub
So as you can see, above I am prompting the user to open a text file, afterwards it is displayed back to the user in a datagridview.
Now here is my issue, I want to be able to query the data, E.g. Select * From URLs WHERE active='1' (Too used to PHP + MySQL!)
Where the 1 is the corresponding 1 or 0 after the URL in the text file.
In the above example the data is being stored in a simple class as per below:
Public Class Test
Public Sub New(ByVal URL As String, ByVal Active As Integer)
_URL = URL
_Active = Active
End Sub
Private _URL As String
Public Property URL() As String
Get
Return _URL
End Get
Set(ByVal value As String)
_URL = value
End Set
End Property
Private _Active As String
Public Property Active As String
Get
Return _Active
End Get
Set(ByVal value As String)
_Active = value
End Set
End Property
End Class
Am I going completely the wrong way about storing the data after importing from a text file?
I am new to VB.NET and still learning the basics but I find it much easier to learn by playing around before hitting the massive books!
Working example:
Dim myurls As New List(Of Test)
myurls.Add(New Test("http://link1.com/", 1))
myurls.Add(New Test("http://link2.com/", 0))
myurls.Add(New Test("http://link3.com/", 0))
Dim result = From t In myurls Where t.Active = 1
For Each testitem As Test In result
MsgBox(testitem.URL)
Next
By the way, LINQ is magic. You can shorten your loading/parse code to 3 rows of code:
Dim Lines() = IO.File.ReadAllLines("myfile.txt")
Dim myurls As List(Of Test) = (From t In lines Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
DataGridViewX1.DataSource = myurls
The first line reads all lines in the file to an array of strings.
The second line splits each line in the array, and creates a test-item and then converts all those result items to an list ( of Test).
Of course this could be misused to sillyness by making it to a one-row:er:
DataGridViewX1.DataSource = (From t In IO.File.ReadAllLines("myfile.txt") Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
Wich would render your load function to contain only following 4 rows:
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
DataGridViewX1.DataSource = (From t In IO.File.ReadAllLines("myfile.txt") Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
LabelX5.Text = ctype(datagridviewx1.datasource,List(Of Test)).Count
End If
You can query your class using LINQ, as long as it is in an appropriate collection type, like List(of Test) . I am not familiar completely with the VB syntax for LINQ but it would be something like below.
list.Where(Function(x) x.Active == "1").Select(Function(x) x.Url)
However, this isnt actually storing anything into a database, which i think your question might be asking?
I think you are reinventing the wheel, which is not generally a good thing. If you want SQL like functionality just store the data in a SQL DB and query it.
There are a lot of reasons you should just use an existing DB:
Your code will be less tested and thus more likely to have bugs.
Your code will be less optimized and probably perform worse. (You were planning on implementing a query optimizer and indexing engine for performance, right?)
Your code won't have as many features (locking, constraints, triggers, backup/recovery, a query language, etc.)
There are lots of free RDBMS options out there so it might even be cheaper to use an existing system than spending your time writing an inferior one.
That said, if this is just an academic exercise, go for it. However, I wouldn't do this for a real-world system.