Using a combo box to store items in an array from a text file and then using that array and its components in another form - vb.net

I'm currently designing an application within visual basic using vb.net. The first form asks for login information and then prompts the next form to select a customer. The customer information is stored in a text file that gets put in an array. I next have a form for the user to display and edit that information. How can I use the array I already created in the previous form in my display and edit form?
Private Sub frmCustomerList_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sr As StreamReader = File.OpenText("customer.txt")
Dim strLine As String
Dim customerInfo() As String
Do While sr.Peek <> -1
strLine = sr.ReadLine
customerInfo = strLine.Split("|")
cboCustomers.Items.Add(customerInfo(0))
customerList(count) = strLine
count = count + 1
Loop
End Sub
Private Sub cboCustomers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboCustomers.SelectedIndexChanged
Dim customerInfo() As String
Dim index As Integer = cboCustomers.SelectedIndex
Dim selectedCustomer As String = customerList(index)
customerInfo = selectedCustomer.Split("|")
End Sub

Make the next form require it in the constructor:
Public Class EditCustomer
Public Sub New(customerInfo As String())
InitializeComponent() 'This call is required, do not remove
'Yay! Now you have your info
End Sub
End Class
You'd call it by doing something like...
Dim editForm = New EditCustomerFrom(customerInfo)
editForm.Show()
Alternatively, you could have a property on the form you set.
Dim editForm = New EditCustomerFrom()
editForm.Customer = customerInfo
editForm.Show()
Then inside the Load event of that form, you'd write the logic that would display it looking at that property.
Aside: You should look at maybe defining an object to hold customer info and do some JSON or XML serialization for reading/writing to the file, IMO. This architecture is kind of not good as is....

Related

Is there a way to extract a variable from a subroutine in vb .net? or how do I declare custom event handlers and trigger them in a linked fashion?

I am trying to build this file copy utility in VB.Net, and I have this window:
The current folder button opens up a folder browser dialog, and I save the selected path from the dialog to a string variable which I then pass to a function. The function adds all files and directories present in that folder to the current folder listbox.
Now I need this filepath for the all files checkbox, which when triggered lists all the subdirectories and their contents in the currentfolder listbox.
Is there any way I can extract that filepath variable dynamically without hardcoding it? Or can I create custom event handlers and trigger them inside the current folder button handler?
Here is my code:
Public Class Form1
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim FB As FolderBrowserDialog = New FolderBrowserDialog()
Dim srcpath As String
Dim flag As Integer = 1
FB.ShowDialog()
FB.ShowNewFolderButton = True
If (DialogResult.OK) Then
srcpath = FB.SelectedPath()
End If
listfiles(srcpath)
End Sub
Public Function listfiles(srcpath As String)
Dim dir As DirectoryInfo = New DirectoryInfo(srcpath)
Dim dirs As DirectoryInfo() = dir.GetDirectories()
Dim d As DirectoryInfo
Dim files As FileInfo() = dir.GetFiles()
Dim file As FileInfo
For Each file In files
CurrentFolderListBox.Items.Add(file.Name)
Next
For Each d In dirs
CurrentFolderListBox.Items.Add(d)
Next
'If CheckBox1.Checked = True Then
' CheckBox1_CheckedChanged(sender, New System.EventArgs())
'End If
End Function
Public Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChange
Dim item As DirectoryInfo
For Each i As DirectoryInfo In CurrentFolderListBox.Items
item = i
Next
End Sub
Any help would be most appreciated.
Well, for the list side lbox, and the right side lbox?
Why not fill each list box with a data source? You can have 1, or 2, or even 5 columns of data. The ListBox can display TWO of the columns.
So, VERY often a list box will have two values. the "value" based on what you select (often a PK database row value), and then you have the "text" value for display.
from FoxPro, ms-access, vb.net, and even asp.net?
A list box traditional has had the ability to "store" a set of values for your selection.
So, why not just put out the file list to a on the fly "data structure". You can quite much use a struct, a class or whatever.
However, might as well use a data table, since listbox supports "binding" to a table.
So, in the ListBox settings, you have these two settings:
so above is our "display"
And then set the "value" to the FULL file name like this:
So now we can say create a form like this:
So, our code to select the "from folder" can look like this:
Private Sub cmdSelFrom_Click(sender As Object, e As EventArgs) Handles cmdSelFrom.Click
Dim f As New FolderBrowserDialog
If f.ShowDialog = DialogResult.OK Then
txtFromFolder.Text = f.SelectedPath
ListBox1.DataSource = GetFileData(txtFromFolder.Text)
End If
End Sub
Public Function GetFileData(sFolder As String) As DataTable
Dim rstData As New DataTable
rstData.Columns.Add("FullFile", GetType(String))
rstData.Columns.Add("FileName", GetType(String))
' get all files from this folder
Dim folder As New DirectoryInfo(sFolder)
Dim fList() As FileInfo = folder.GetFiles
For Each MyFile As FileInfo In fList
Dim OneRow As DataRow = rstData.NewRow
OneRow("FullFile") = MyFile.FullName
OneRow("FileName") = MyFile.Name
rstData.Rows.Add(OneRow)
Next
Return rstData
End Function
so, we setup a two column "thing" (in this case a data table).
We fill it with our two values (FileName and FullFile).
So, we now have this:
I have selected two files on the left side, and thus we get this:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
For Each MySel As DataRowView In ListBox1.SelectedItems
Debug.Print(MySel.Item("FileName"))
Debug.Print(MySel.Item("FullFile"))
Next
End Sub
OutPut:
a.pdf
C:\Test2\a.pdf
b.pdf
C:\Test2\b.pdf
We could even include say file size in that table. But the "basic" concept here is that we can store + save data items into the list box, and that REALLY makes the code simple, since the list box now has JUST the file for display, but also enables us to have the full path name also.

Select random element from array and display in textbox

I have a form with a button and a textbox. I also have a text file with the following contents..
Bob:Available:None:0
Jack:Available:None:0
Harry:Available:None:0
Becky:Unavailable:Injured:8
Michael:Available:None:0
Steve:Available:None:0
Annie:Unavailable:Injured:8
Riley:Available:None:0
When the user loads the form each value of the text file gets stored into an array. This works fine. What i would like to happen is when the button is pressed a random person (name) who has the value 'Available' will be retrieved from the array and displayed in the textbox.
The code i have so far (which stores each item in text file into arrays):
Public Class Form1
'define profile of person
Public Structure PersonInfo
Public name As String
Public status As String
Public status_type As String
Public monthsunavailable As Integer
End Structure
'Profile List of persons
Public Shared personInfos As New List(Of PersonInfo)() 'roster data
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'read all infomations of person from file. lines is profile array
Dim lines() As String = IO.File.ReadAllLines(filelocation)
For Each line In lines
'Parses the line string, make Person Info and add it to Person List
'split string with ":"
If line.Trim.Equals("") Then Continue For
Dim strArr() = line.Split(":")
'make Person Info
Dim pi As New PersonInfo()
pi.name = strArr(0)
pi.status = strArr(1)
pi.status_type = strArr(2)
pi.monthsunavailable = strArr(3)
'add Person Info to Person List
personInfos.Add(pi)
Next
How do i select a random name from the array and display it in a textbox?
You can use something like this. Try reading the docs!
Private Sub Button1_click (sender As Object, e As EventArgs) Handles Button1.Click
Dim r As New Random ()
Textbox1.Text = personinfos(r.Next (0,personinfos.count)).name
End Sub
Update
To select only names with status "Available"
Private Sub Button1_click (sender As Object, e As EventArgs) Handles Button1.Click
'Instantiate a new random variable
Dim r As New Random ()
'This is a LINQ query to select all items from the list where a property of the item
'(in this case , status) is equal to something.
'Try changing Available to something else and see what you get
Dim qr = From pi in personinfos
Where pi.status = "Available"
Select pi
'The following line can be simplified as follows
'Dim i As Integer = r.Next (0,qr.count)
'Dim s As String = qr (i).name
'Textbox1.Text = s
Textbox1.Text = qr(r.Next (0,qr.count)).name
End Sub

VB.NET DataSet table data empty

I'm trying to use the dataset for a report, but the data is gone when I try to use it. Here is my code for the most part:
Variables:
Dim ResultsDataView As DataView
Dim ResultsDataSet As New DataSet
Dim ResultsTable As New DataTable
Dim SQLQuery As String
Search:
This is where a datagrid is populated in the main view. The data shows up perfectly.
Private Sub Search(Optional ByVal Bind As Boolean = True, Optional ByVal SearchType As String = "", Optional ByVal SearchButton As String = "")
Dim SQLQuery As String
Dim ResultsDataSet
Dim LabelText As String
Dim MultiBudgetCenter As Integer = 0
SQLQuery = "A long and detailed SQL query that grabs N rows with 7 columns"
ResultsDataSet = RunQuery(SQLQuery)
ResultsTable = ResultsDataSet.Tables(0)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
sb.Append(item.ToString + ","c)
Response.Write(item.ToString + "\n")
Response.Write(vbNewLine)
Next
sb.Append(vbCr & vbLf)
Next
'Response.End()
If Bind Then
BindData(ResultsDataSet)
End If
End Sub
Binding Data:
I think this is a cause in the issue.
Private Sub BindData(ByVal InputDataSet As DataSet)
ResultsDataView = InputDataSet.Tables("Results").DefaultView
ResultsDataView.Sort = ViewState("SortExpression").ToString()
ResultsGridView.DataSource = ResultsDataView
ResultsGridView.DataBind()
End Sub
Reporting action:
This is where I am trying to use the table data. But it is showing as nothing.
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
The reason I'm trying to loop through this data is to both display the data in a gridview on the main view as well as export the data to CSV. If there is a different way to export a SQL query to CSV, I'm open to any suggestions.
There has to be something I can do to get the data from the SQL query to persist through the ReportButton_Click method. I've tried copying the datatable, I've tried global variables, I've tried different methods of looping through the dataset. What am I missing?!
Thank you all in advance.
EDIT
Here is the Page_Load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
'set focus to postback control
Dim x As String = GetPostBackControlName(Page)
If Len(x) > 0 Then
x = x.Replace("$", "_")
SetFocus(x)
End If
End If
If Not IsPostBack Then
ResultsGridView.AllowPaging = False
'Enable Gridview sorting
ResultsGridView.AllowSorting = True
'Initialize the sorting expression
ViewState("SortExpression") = "ID DESC"
'Populate the Gridview
Search()
End If
End Sub
In your search function add this line after the ResultsTable setting
ResultsTable = ResultsDataSet.Tables(0)
Session("LastSearch") = ResultsTable
Then in your report click event handler recover your data from the Session variable
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
ResultsTable = DirectCast(Session("LastSearch"), DataTable)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
You need to read about ASP.NET Life Cycle and understand that every time ASP.NET calls your methods it creates a new instance of your Page class. Of course this means that global page variables in ASP.NET are not very useful.
Also consider to read about that Session object and not misuse it.
What is the difference between SessionState and ViewState?

VB.NET Program is always reading last created textfile

Trying to create a login form,
My coding is currently:
Imports System
Imports System.IO
Public Class frmLogin
Dim username As String
Dim password As String
Dim fileReader As String
Dim folderpath As String
Dim files As Integer
Dim filepath As String
Public Structure info
Dim U As String
Dim P As String
End Structure
Dim details As info
Private Sub btnlogin_Click(sender As Object, e As EventArgs) Handles btnlogin.Click
If txtusername.Text = details.U And txtpassword.Text = details.P Then
MessageBox.Show("Correct!")
frmmenu.Show()
Me.Hide()
Else
MessageBox.Show("wrong")
txtusername.Clear()
txtpassword.Clear()
End If
End Sub
Private Sub btncreate_Click(sender As Object, e As EventArgs) Handles btncreate.Click
frmcreate.Show()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
files = files + 1
filepath = "C:\Users\TheGlove\Desktop\Alex's Program\loginfile" & files & ".txt"
Dim di As DirectoryInfo = New DirectoryInfo("C:\Users\TheGlove\Desktop\Alex's Program")
folderpath = "C:\Users\TheGlove\Desktop\Alex's Program"
files = System.IO.Directory.GetFiles(folderpath, "*.txt").Count
For Each fi In di.GetFiles()
MsgBox(fi.Name)
Dim FILE = System.IO.File.ReadAllLines("C:\Users\TheGlove\Desktop\Alex's Program\loginfile" & files & ".txt")
Dim myArray As String() = FILE
details.U = myArray(0)
details.P = myArray(1)
Next
End Sub
End Class
Button 1 will be merged with btnlogin when i get it working and for now is currently just a seperate button to read each textfile.
When each button is pressed (Button 1 -> btnlogin), only the last created textfile is correct.
By the looks of things, your code does read all the text files, but keeps overwriting details.u and details.p with the value retrieved from each file. So, when the loop gets to the last file, those values are what ends up in the details object.
I'm assuming that you want to read all the usernames and passwords into a list and check the details in the TextBoxes against that list, so .. Your code should probably be something like the code below (see the code comments for an explanation of some of the differences.
Before we get to the code, can give you a couple of pointers.
Firstly, always try to use names that are meaningful. Defining your structure as Info is not as meaningful as it could be. For example, you would be better calling it UserInfo and rather than use P and U, you would be better using Password and UserName. It may not matter so much right now, but when you start writing larger more complex programs, and have to come back to them in 6 months time to update them, info.P or details.P aren't as informative as the suggested names.
Secondly, as #ajd mentioned. Don't use magic strings. Create one definition at the beginning of your code which can be used throughout. Again it makes maintenance much easier if you only have to change a string once instead of multiple times, and reduces the chance of mistakes.
Finally, several of the variables you have defined aren't used in your code at all. Again, at this level, it isn't a major issue, but with large programs, you could end up with a bigger memory footprint than you want.
Dim username As String
Dim password As String
Dim fileReader As String
Dim folderpath As String = "C:\Users\TheGlove\Desktop\Alex's Program"
Dim files As Integer
Dim filepath As String
Public Structure UserInfo
Dim Name As String
Dim Password As String
End Structure
'Change details to a list of info instead of a single instance
Dim userList As New List(Of UserInfo)
Private Sub Btnlogin_Click(sender As Object, e As EventArgs) Handles btnlogin.Click
'Iterate through the list of details, checking each instance against the textboxes
For Each tempUserInfo As UserInfo In userList
If txtusername.Text = tempUserInfo.Name And txtpassword.Text = tempUserInfo.Password Then
MessageBox.Show("Correct!")
frmmenu.Show()
Me.Hide()
'This is here, because after your form has opened an closed, the loop
'that checks usernames and passwords will continue. The line below exits the loop safely
Exit For
Else
MessageBox.Show("wrong")
txtusername.Clear()
txtpassword.Clear()
End If
Next
End Sub
Private Sub Btncreate_Click(sender As Object, e As EventArgs) Handles btncreate.Click
frmcreate.Show()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'clear the list of user details otherwise, if the files are loaded a second time,
'you'll get the same details added again
userList.Clear()
'This line replaces several lines in your code that searches the folder for files
'marching the search pattern
Dim fileList() As FileInfo = New DirectoryInfo(folderpath).GetFiles("loginfile*.txt")
For Each fi As FileInfo In fileList
MsgBox(fi.Name)
Dim userDetails() As String = System.IO.File.ReadAllLines(fi.FullName)
Dim tempInfo As New UserInfo With {.Name = userDetails(0), .Password = userDetails(1)}
'An expanded version of the above line is
'Dim tempInfo As New info
'tempInfo.U = userDetails(0)
'tempInfo.P = userDetails(1)
userList.Add(tempInfo)
Next
files = fileList.Count
End Sub

persisting textbox text in visual basic

I am pretty new to VB and am compiling a program which contains several forms, each of which is populated with text boxes. The purpose of the program is for text to be dragged between boxes to move assets around. I've managed the drag and drop functionality but need to persist the text in the text boxes once the program is shut down so that when reopened, the last location of all moved text is still present.
Can anyone make any suggestions/supply sample code please?
I've tried the easiest to understand suggestion to get me started but when I build and publish the program it says that I do not have access to the file to save the values!! Can anyone help? Code below
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim txtpersist As IO.TextWriter = New IO.StreamWriter("C:\Users\HP\Documents\namestore")
txtpersist.WriteLine(TextBox1.Text)
txtpersist.WriteLine(TextBox2.Text)
txtpersist.WriteLine(TextBox3.Text)
txtpersist.Close()
Dim yourfile As IO.TextReader = New IO.StreamReader("C:\Users\HP\Documents\namestore")
TextBox1.Text = yourfile.ReadLine()
TextBox2.Text = yourfile.ReadLine()
TextBox3.Text = yourfile.ReadLine()
yourfile.Close()
End Sub
End Class
You can use the built in PropertyBinding to link your TextBox.Text to a Property. It will put it into your App.Config File which will allow you to edit it through MySettings as long as it is per user. If the settings are application level you would be better of using one of the other answers. You can also look at this article for some more information.
You should write the location of the textboxes to a persistent store on program exit, such as a file, a database, or the registry. On program load, you can retrieve the saved values and set the locations accordingly.
You could save each textbox's text inside of a file and re-open it at runtime.
Dim yourfile As TextWriter = New StreamWriter("pathtofile")
Say you had 3 textBoxes called textBox1, textBox2 and textBox3. You would save each one's status by simply writing each textbox's text property inside the file. Like so:
yourfile.WriteLine(textBox1.Text)
yourfile.WriteLine(textBox2.Text)
yourfile.WriteLine(textBox3.Text)
At the end, you just close the file.
yourfile.Close()
Loading the data back is just as simple.
Dim yourfile As TextReader = New StreamReader("pathtofile")
textBox1.Text = yourfile.ReadLine()
textBox2.Text = yourfile.ReadLine()
textBox3.Text = yourfile.ReadLine()
yourfile.Close()
Let me know if you have any questions or require further assistance. Be sure to import the System.IO namespace, to get access to the IO classes used here.
The most common method of persisting data is to store it in a database. Of course that adds more work to your project since you now have to create, update, and maintain a database. An easier solution is to use a file.
We'll create a new class in order to read & write data from the file. This way if you switch to a database later on, you only need to change the class. And since I'm sure at some point you'll want a database we'll make the class use datatables to minimize the changes needed to it. Here's our class:
Public Class TextBoxes
Private tbl As DataTable
Private filename As String
'Use constants for our column names to reduce errors
Private Const ctrlName As String = "CtrlName"
Private Const text As String = "Text"
Public Sub New(ByVal file As String)
'Create the definition of our table
tbl = New DataTable("TextBox")
tbl.Columns.Add(ctrlName, Type.GetType("System.String"))
tbl.Columns.Add(text, Type.GetType("System.String"))
'Save the filename to store the data in
Me.filename = file
End Sub
Public Sub Save(ByVal frm As Form)
Dim row As DataRow
'Loop through the controls on the form
For Each ctrl As Control In frm.Controls
'If the control is a textbox, store its name & text in the datatable
If TypeOf (ctrl) Is TextBox Then
row = tbl.NewRow
row.Item(ctrlName) = ctrl.Name
row.Item(text) = ctrl.Text
tbl.Rows.Add(row)
End If
Next
'Save the additions to the dataset and write it out as an XML file
tbl.AcceptChanges()
tbl.WriteXml(filename)
End Sub
Public Sub Load(ByVal frm As Form)
'Don't load data if we can't find the file
If Not IO.File.Exists(filename) Then Return
tbl.ReadXml(filename)
For Each row As DataRow In tbl.Rows
'If this control is on the form, set its text property
If frm.Controls.ContainsKey(row.Item(ctrlName)) Then
CType(frm.Controls(row.Item(ctrlName)), TextBox).Text = row.Item(text).ToString
End If
Next
End Sub
End Class
Next you'll want to use this fine class to read & write your data. The code for doing this is nice and simple:
Dim clsTextBoxes As New TextBoxes("C:\Txt.xml")
'Save the textboxes on this form
clsTextBoxes.Save(Me)
'Load the textboxes on this form
clsTextBoxes.Load(Me)
I would do it using either the Application settings as Mark Hall pointed out or like this...
Public Class MyTextBoxValueHolder
Public Property Value1 As String
Public Property Value2 As String
Public Property Value3 As String
Public Sub Save(Path As String)
Dim serializer As New XmlSerializer(GetType(MyTextBoxValueHolder))
Using streamWriter As New StreamWriter(Path)
serializer.Serialize(streamWriter, Me)
End Using
End Sub
Public Shared Function Load(Path As String) As MyTextBoxValueHolder
Dim serializer As New XmlSerializer(GetType(MyTextBoxValueHolder))
Using streamReader As New StreamReader(Path)
Return DirectCast(serializer.Deserialize(streamReader), MyTextBoxValueHolder)
End Using
End Function
End Class
So what you can then do is...
Dim myValues As MyTextBoxValueHolder = MyTextBoxValueHolder.Load("SomeFilePath.xml")
myTextBox1.Text = myValues.Value1
myTextBox2.Text = myValues.Value2
'And so on....
2 Save
Dim myValues As New MyTextBoxValueHolder
myValues.Value1 = myTextBox1.Text
myValues.Value2 = myTextBox2.Text
myValues.Save("SomeFilePath.xml")
'All saved
to maintain the values ​​you can use stored user settings, see the following links.
http://msdn.microsoft.com/en-us/library/ms379611(v=vs.80).aspx
http://www.codeproject.com/KB/vb/appsettings2005.aspx
Regards.