Creating a Variable with StreamReader Split Results - vb.net

I've recently been exposed to vb.net scripting and I am having some trouble figuring out how to accomplish a task. I'm supposed to create a program that will automate an end user process but right now it only works for one specific id(because I've hardcoded a value to make the script run). I've scripted the use of StreamReader to loop through all the possible entries, but I can't figure out how to put that result into a variable so the program will automatically read the id selected and proceed through the steps, then loop until all id's identified via StreamReader have been processed. I apologize if this has been asked before, I am not very familiar with the terminology.
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
Application.DoEvents()
End
End Sub
Private Sub Form1_FormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
uxNote.Text = "Starting"
Me.Update()
RunApp()
Me.Close()
End Sub
Sub RunApp()
Dim b As New BostonWorkStation
Dim myHandle As Long
b.Shell_("C:\Software\Application.exe")
b.Activate("AppCaption", True)
b.Connect("AppCaption", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Update()
b.Wait(2)
b.Pause("#378,423")
b.Tab_("user")
b.Enter("password")
b.Wait(2)
b.Shell_("C:\Software\Application2.exe")
b.Activate("App2Caption", True)
b.Wait(4)
b.Connect("App2Caption", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Update()
b.Wait(4)
b.Smart.Create("App2Caption#726,1088", -1024, -633, 0)
b.Smart.Click(False, False)
b.Wait(3)
b.Activate("Patient Lookup", True)
b.Connect("Patient Lookup", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Update()
b.Wait(1)
b.Pause("#104,423")
ProcessPatients(b)
b.Enter("10001") 'hardcoded id this is where I would like a variable to pull in the value
b.Wait(2)
'some more code steps here specific to what should be done once patient id has been selected
End Sub
Sub ProcessPatients(ByVal w As BostonWorkStation)
Dim record() As String
Dim sr As New StreamReader("my path for csv or txt file")
Do While sr.Peek > -1
record = sr.ReadLine.Split(CChar("|"))
Loop
sr.Close()
End Sub

I imagine it would look something like this:
Imports System.IO
Public Class Form1
Private Sub Form1_FormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
uxNote.Text = "Starting"
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
RunApp()
End Sub
Sub RunApp()
Dim b As New BostonWorkStation
Dim myHandle As Long
b.Shell_("C:\Software\Application.exe")
b.Activate("AppCaption", True)
b.Connect("AppCaption", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Refresh()
Application.DoEvents()
b.Wait(2)
b.Pause("#378,423")
b.Tab_("user")
b.Enter("password")
b.Wait(2)
b.Shell_("C:\Software\Application2.exe")
b.Activate("App2Caption", True)
b.Wait(4)
b.Connect("App2Caption", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Refresh()
Application.DoEvents()
b.Wait(4)
b.Smart.Create("App2Caption#726,1088", -1024, -633, 0)
b.Smart.Click(False, False)
b.Wait(3)
b.Activate("Patient Lookup", True)
b.Connect("Patient Lookup", enumStreamType1.stWindows)
uxNote.Text = myHandle.ToString
Me.Refresh()
Application.DoEvents()
b.Wait(1)
b.Pause("#104,423")
ProcessPatients(b)
Me.Close()
End Sub
Sub ProcessPatients(ByVal w As BostonWorkStation)
Dim ID As String
Dim record() As String
Dim sr As New StreamReader("my path for csv or txt file")
Do While Not sr.EndOfStream
record = sr.ReadLine.Split(CChar("|"))
ID = record(0) ' <-- grab your "ID" from somewhere in "record"
w.Enter(ID)
w.Wait(2)
'some more code steps here specific to what should be done once patient id has been selected
Loop
sr.Close()
End Sub
End Class

Related

Forwarding the min and max values of BackgroundWorker to use the function correctly

I have been struggling for several days to find a solution on how to properly incorporate BackgroundWorker into my Feature and with that I have the ability to properly display the process development, process stop, report.
this is my code
Private Sub Frm_ImportLeumobileGK_FormClosing(sender As Object, e As Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
Me.BackgroundWorker1.CancelAsync()
Me.Timer1.Enabled = False
Me.DialogResult = DialogResult.Cancel
e.Cancel = True
End Sub
Private Sub Btn_OK_Click(sender As Object, e As EventArgs) Handles btn_OK.Click
ListView1.Items.Clear()
resetCounter()
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
TestPut_All_CDRs_To_FakturaPos(worker, e,
MasterMandantConnectionString:=MasterMandantConnectionString,
StartDate:=dtp_Start.Value,
EndDate:=dtp_End.Value,
min_Nr:=tb_Min_Nr.Value,
max_Nr:=tb_Max_Nr.Value)
End Sub
Sub TestPut_All_CDRs_To_FakturaPos(worker As BackgroundWorker, e As DoWorkEventArgs, MasterMandantConnectionString As String, StartDate As Date, EndDate As Date, min_Nr As Integer, max_Nr As Integer)
Dim n As Integer = 0
Dim MobCdrs As List(Of String)
ProgressBar1.Maximum = (max_Nr - min_Nr)
For Mob_Nr = min_Nr To max_Nr
n += 1
If worker.CancellationPending Then
e.Cancel = True
Else
MobCdrs = TestPut_Mob_CDRs_To_FakturaPos(MasterMandantConnectionString:=MasterMandantConnectionString,
StartDate:=StartDate,
EndDate:=EndDate,
Mob_Nr:=Mob_Nr)
For Each currentError In MobCdrs
If (currentError <> "") Then
ListView1.Items.Add(currentError)
End If
Next
If n > ProgressBar1.Maximum Then
n = ProgressBar1.Maximum
End If
ProgressBar1.Value = n
End If
Next
ListView1.Items.Insert(0, getImportInfo(), 0)
labelInfo.Text = "Test successfully completed."
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
End Sub
Private Sub Frm_FormClosing(sender As Object, e As Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
If BackgroundWorker1 IsNot Nothing Then
Me.BackgroundWorker1.CancelAsync()
Me.Close()
End If
End Sub
Using Documentation, I tried to apply BackgroundWorker to my "TestPut_All_CDRs_To_FakturaPos" function, unfortunately failed because I get on ProgressBar1.Maximum error = ***"System.InvalidOperationException: "Invalid cross threading operation: The ProgressBar1 control was accessed from a thread other than the thread it was created for."***Please suggest, where am I making an exception?
What you need to do is separate the user interface parts (like ListViews, MessageBoxes, etc.) from the backgroundworker.
The way to get the data into the BGW is to pass an object into its .Argument.
To get data out of it while it is running, use the ReportProgress event and pass whatever you want in the .UserState object.
To get data from it when it has finished, use the .Result property.
We won't be using any result in this case, but I will set it up as a Boolean in case you want to modify it. So, let's create classes to get the data in and out...
Private Class BgwArgs
Property StartDate As DateTime
Property EndDate As DateTime
Property MinNr As Integer
Property MaxNr As Integer
Property ConnStr As String
End Class
Private Class ProgressReportData
Property ErrorMessages As List(Of String)
End Class
The initial setup for the BGW is like this:
Private Sub Btn_OK_Click(sender As Object, e As EventArgs) Handles Btn_OK.Click
ListView1.Items.Clear()
ResetCounter()
Dim args As New BgwArgs With {.StartDate = dtp_Start.Value,
.EndDate = dtp_End.Value,
.MinNr = CInt(tb_Min_Nr.Value),
.MaxNr = CInt(tb_Max_Nr.Value),
.ConnStr = "your connection string"}
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = 100
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.RunWorkerAsync(args)
End Sub
and then all the parts:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
e.Result = TestPut_All_CDRs_To_FakturaPos(worker, e)
End Sub
Private Function TestPut_All_CDRs_To_FakturaPos(worker As BackgroundWorker, e As DoWorkEventArgs) As Boolean
Dim importedInfo As New List(Of String)
Dim args = CType(e.Argument, BgwArgs)
Dim masterMandantConnectionString = args.ConnStr
Dim startDate = args.StartDate
Dim endDate = args.EndDate
Dim min_Nr = args.MinNr
Dim max_Nr = args.MaxNr
Dim n As Integer = 0
Dim totalMobs = max_Nr - min_Nr + 1
For mob_Nr = min_Nr To max_Nr
n += 1
If worker.CancellationPending Then
e.Cancel = True
Else
Dim mobCdrs = TestPut_Mob_CDRs_To_FakturaPos(MasterMandantConnectionString:=masterMandantConnectionString,
StartDate:=startDate,
EndDate:=endDate,
Mob_Nr:=mob_Nr)
Dim pct = n * 100 \ totalMobs
Dim progReport As New ProgressReportData With {.ErrorMessages = mobCdrs.Where(Function(m) Not String.IsNullOrEmpty(m)).ToList()}
worker.ReportProgress(pct, progReport)
End If
Next
Return True
End Function
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Dim progData = CType(e.UserState, ProgressReportData)
ProgressBar1.Value = e.ProgressPercentage
If progData.ErrorMessages IsNot Nothing Then
For Each m In progData.ErrorMessages
ListView1.Items.Add(m)
Next
End If
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If (e.Error IsNot Nothing) Then
ProgressBar1.ForeColor = Color.Red
MessageBox.Show(e.Error.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error)
ElseIf e.Cancelled Then
' Next, handle the case where the user cancelled the operation.
' Note that due to a race condition in the DoWork event handler, the Cancelled flag may not have been set, even though CancelAsync was called.
ProgressBar1.ForeColor = Color.HotPink
Else
ProgressBar1.ForeColor = Color.LawnGreen
ListView1.Items.Insert(0, GetImportInfo(), 0)
labelInfo.Text = "Test successfully completed."
' We could use e.Result here if something useful was returned in it.
' Dim flag = CType(e.Result, Boolean)
End If
End Sub
The progress percentage is calculated in the loop, as that's an easy way to get it done.
I couldn't test it, but hopefully there's enough there for you to get working code.
(I use Option Infer On and Option Strict On.)

How to show records added to datagridview in real time

A co-worker needs to search our network and her File Explorer search does not work well. I threw this app together quickly to allow her to search and it works well. The results are written to a datagridview, but the results are not shown until the search is complete.
I would like the datagridview to show records as they are added and allow her to cancel the search if she wants.
Using a backgroundworker, I tried to refresh the grid, but as soon as it finds a match, the code stops running. There are no errors, it just stops running.
So how can I get the grid to update as it continues to search?
Public dtResults As DataTable
Dim myDataSet As New DataSet
Dim myDataRow As DataRow
Dim colType As DataColumn
Dim colResult As DataColumn
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtResults = New DataTable()
colType = New DataColumn("Type", Type.GetType("System.String"))
colResult = New DataColumn("Search Result", Type.GetType("System.String"))
dtResults.Columns.Add(colType)
dtResults.Columns.Add(colResult)
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End Sub
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
btnSearch.Enabled = False
sbStatusBar.Text = "Searching..."
dtResults.Clear()
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
LoopSubFolders(txtSearchLocation.Text)
End Sub
Public Sub LoopSubFolders(sLocation As String)
Dim di = New DirectoryInfo(sLocation)
Dim mySearchterm As String = LCase(txtSearchTerm.Text)
Dim fiArr As FileInfo() = di.GetFiles()
Dim sSearchTarget As String
sbStatusBar.Text = "Searching " & sLocation
'Search File names in
If cbFileNames.Checked = True Then
For Each myFile In fiArr
sSearchTarget = LCase(myFile.Name)
If sSearchTarget.Contains(mySearchterm) Then
myDataRow = dtResults.NewRow()
myDataRow(dtResults.Columns(0)) = "File"
myDataRow(dtResults.Columns(1)) = Path.Combine(sLocation, myFile.Name)
dtResults.Rows.Add(myDataRow)
End If
Next
End If
For Each d In Directory.GetDirectories(sLocation)
If cbFolderNames.Checked = True Then
sSearchTarget = LCase(d)
If sSearchTarget.Contains(mySearchterm) Then
myDataRow = dtResults.NewRow()
myDataRow(dtResults.Columns(0)) = "Folder"
myDataRow(dtResults.Columns(1)) = d
dtResults.Rows.Add(myDataRow)
End If
End If
LoopSubFolders(d)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
btnSearch.Enabled = True
sbStatusBar.Text = "Complete"
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End Sub
Here's an example of how you might do it using the suggested ReportProgress method and ProgressChanged event:
Private table As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Configure table here.
DataGridView1.DataSource = table
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Setup UI here.
'Note that you MUST pass in the TextBox data as you MUST NOT touch the UI directly on the secondary thread.
BackgroundWorker1.RunWorkerAsync({TextBox1.Text, TextBox2.Text})
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Get the data passed in and separate it.
Dim arguments = DirectCast(e.Argument, String())
Dim folderPath = arguments(0)
Dim searchTerm = arguments(1)
SearchFileSystem(folderPath, searchTerm)
End Sub
Private Sub SearchFileSystem(folderPath As String, searchTerm As String)
For Each filePath In Directory.GetFiles(folderPath)
If filePath.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) <> -1 Then
'Update the UI on the UI thread.
BackgroundWorker1.ReportProgress(0, {"File", filePath})
End If
Next
For Each subfolderPath In Directory.GetDirectories(folderPath)
If subfolderPath.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) <> -1 Then
'Update the UI on the UI thread.
BackgroundWorker1.ReportProgress(0, {"Folder", subfolderPath})
End If
SearchFileSystem(subfolderPath, searchTerm)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'Get the data passed out and separate it.
Dim data = DirectCast(e.UserState, String())
'Update the UI.
table.Rows.Add(data)
End Sub
Note that you should NEVER touch the UI directly in the DoWork event handler or a method called from it. ONLY touch the UI on the UI thread. That means that the text in your TextBoxes must be extracted BEFORE calling RunWorkerAsync. You can eithewr pass the Strings in as arguments or you can assign them to fields and access them from there on any thread. Don't EVER access a member of a control on other than the UI thread. Some times it will work, sometimes it will appear to work but not do as intended and sometimes it will crash your app. So that you don't have to remember which specific scenarios cause which result, avoid such scenario altogether.
I haven't tested this code so I'm not sure but you may have to call Refresh on the grid or the form after adding the new row to the DataTable.
Variables
Well, let's start from the top with some class level variables:
'Notice the enabled properties.
Private WithEvents BackgroundWorker1 As New BackgroundWorker With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
'To monitor the cancellation, set by the Cancel Button.
Private bgwCancel As Boolean = False
'The DGV source.
Private dtResults As New DataTable
'The start directory.
Private startDir As String
'The search keyword.
Private searchWord As String
'Whether to search the sub directories, from a check box for example.
Private includeSubDirectories As Boolean = True
'Whether to search the files, from another check box.
Private includeFiles As Boolean = True
The Constructor
Prepare your DGV and whatever else you need here.
Sub New()
dtResults.Columns.Add(New DataColumn("Type", Type.GetType("System.String")))
dtResults.Columns.Add(New DataColumn("Search Result", Type.GetType("System.String")))
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
'Make sure you add the image column after binding the data source.
Dim imgCol As New DataGridViewImageColumn(False)
With imgCol
.Image = Nothing
.Name = "imgCol"
.HeaderText = ""
.Width = 50
.DefaultCellStyle.NullValue = Nothing
End With
DataGridView1.Columns.Insert(0, imgCol)
End Sub
Iterator
Now, let's write the search routine. I'd do that through an Iterator function:
Private Iterator Function IterateFolders(startDir As String, includeFiles As Boolean, includeSubDir As Boolean) As IEnumerable(Of String)
For Each dirName In IO.Directory.EnumerateDirectories(startDir)
Yield dirName
If includeFiles Then
For Each fileName In IO.Directory.EnumerateFiles(startDir)
Yield fileName
Next
End If
If includeSubDir Then
For Each subDir In IterateFolders(dirName, includeFiles, includeSubDir)
Yield subDir
Next
End If
Next
End Function
The Main Thread Updater
A routine called by the worker's thread to update the DataTable and any control that belongs to the main thread:
Private Sub AddSearchResult(path As String)
If InvokeRequired Then
Invoke(Sub() AddSearchResult(path))
Else
dtResults.Rows.Add(If(IO.File.Exists(path), "File", "Folder"), path)
sbStatusBar.Text = $"Searching {path}"
End If
End Sub
Start
In the click event of the start button, do the necessary validations, assign the values to their variables, and start the back ground worker:
If String.IsNullOrEmpty(txtSearchKeyword.Text) Then Return
If String.IsNullOrEmpty(txtSearchLocation.Text) Then Return
bgwCancel = False
dtResults.Rows.Clear()
startDir = txtSearchLocation.Text
searchWord = txtSearchKeyword.Text.ToLower
includeSubDirectories = chkIncludeSubDirs.Checked
includeFiles = chkFiles.Checked
btnSearch.Enabled = False
sbStatusBar.Text = "Searching..."
BackgroundWorker1.RunWorkerAsync()
Cancel
To cancel the search, in the click event of the cancel button I presume, True the bgwCancel variable:
bgwCancel = True
The BackgroundWorker - DoWork
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For Each item As String In IterateFolders(startDir, includeFiles, includeSubDirectories)
If bgwCancel Then
BackgroundWorker1.CancelAsync()
Return
End If
If item.ToLower.Contains(searchWord) Then
AddSearchResult(item)
End If
Threading.Thread.Sleep(100)
Next
End Sub
Note that, Its good practice to give a lengthy routine a BREATH through the Sleep(ms) method of that thread.
The BackgroundWorker - ProgressChanged
I don't think you need it here.
The BackgroundWorker - RunWorkerCompleted
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If bgwCancel Then
sbStatusBar.Text = "Canceled!"
MessageBox.Show("Canceled by you!")
ElseIf e.Error IsNot Nothing Then
sbStatusBar.Text = "Error!"
MessageBox.Show(e.Error.Message)
Else
sbStatusBar.Text = "Complete"
'YOU DO NOT NEED TO DO THIS. Remove the following
'DataGridView1.DataSource = Nothing
'DataGridView1.DataSource = dtResults
'DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End If
btnSearch.Enabled = True
End Sub
The Image Column
Handle the RowsAdded event of the DGV as follow:
Private Sub DataGridView1_RowsAdded(sender As Object, e As DataGridViewRowsAddedEventArgs) Handles DataGridView1.RowsAdded
If DataGridView1.Columns.Count < 3 Then Return
'if you want to get rid of the default x image.
If e.RowIndex = 0 Then
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = Nothing
End If
Dim path As String = DataGridView1.Rows(e.RowIndex).Cells(2).Value?.ToString
If Not String.IsNullOrEmpty(path) Then
If IO.File.Exists(path) Then
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = Icon.ExtractAssociatedIcon(path).ToBitmap
Else
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = My.Resources.Folder
End If
End If
End Sub
Where the My.Resources.Folder is an icon file of your choice for the folder entries.
Good luck.

Problems Reading File

Currently having issues reading data from a file, and assigning it to the text-boxes on my form. The code runs without throwing an error, but no data/values are passed to the text-boxes and they remain blank. Below is my code:
Imports System.IO
Public Class ReadingEmployeeData
' Declare filename
Dim FileName As String
Private Sub NextButton_Click(sender As Object, e As EventArgs) Handles NextButton.Click
' Constant for holding the number of fields
Const NumFields As Integer = 8
' Declare variables
Dim FileStream As StreamReader
Dim Count As Integer
Try
' Open file
FileStream = File.OpenText(FileName)
' Read the data
For Count = 1 To NumFields
FirstText.Text = FileStream.ReadLine()
MiddleText.Text = FileStream.ReadLine()
LastText.Text = FileStream.ReadLine()
NumberText.Text = FileStream.ReadLine()
DepartmentText.Text = FileStream.ReadLine()
PhoneText.Text = FileStream.ReadLine()
ExtText.Text = FileStream.ReadLine()
EmailText.Text = FileStream.ReadLine()
Next Count
Catch ex As Exception
MessageBox.Show("That file can not be opened.")
Finally
FileStream.Close()
End Try
End Sub
Private Sub ReadingEmployeeData_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Get the filename from user
FileName = InputBox("Please enter the name of the file")
End Sub
Private Sub ExitButton_Click(sender As Object, e As EventArgs) Handles ExitButton.Click
Me.Close()
End Sub
End Class
Try using Io.StreamReader, And there is no need to NumFields:
Imports System.IO
Public Class ReadingEmployeeData
' Declare filename
Dim FileName As String
Private Sub NextButton_Click(sender As Object, e As EventArgs) Handles NextButton.Click
' Declare variables
Dim FileStream As StreamReader
Dim Count As Integer
Try
' Open file
Using sr As New Io.StreamReader(FileName)
' Read the data
FirstText.Text = sr.ReadLine()
MiddleText.Text = sr.ReadLine()
LastText.Text = sr.ReadLine()
NumberText.Text = sr.ReadLine()
DepartmentText.Text = sr.ReadLine()
PhoneText.Text = sr.ReadLine()
ExtText.Text = sr.ReadLine()
EmailText.Text = sr.ReadLine()
sr.Close()
End Using
Catch ex As Exception
MessageBox.Show("That file can not be opened.")
End Try
End Sub
Private Sub ReadingEmployeeData_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Get the filename from user
FileName = InputBox("Please enter the name of the file")
End Sub
Private Sub ExitButton_Click(sender As Object, e As EventArgs) Handles ExitButton.Click
Me.Close()
End Sub
End Class

VB.NET: Code runs without error, but does not add item to listbox

I've got this embedded CMD on my form which I created using another person's code and everything works right. Inside one of the Private Subs (that seems to run every time a new line is written in the CMD output textbox), I've got a line which adds a item to a listbox (listboxs name is txtPlayerList) on another form labelled Status.
When this area of the code runs, it doesn't throw up any errors (and if I put a msgbox() on the same line, the msgbox() works). If I put the add to listbox line on form_load it works perfectly?
Here is my code, I've included everything from that form just in case (it is in the third sub from the top with the asterisks and comment "Get players and maybe other stuff as well"
Imports System.IO
Public Class Console
Public WithEvents MyProcess As Process
Private Delegate Sub AppendOutputTextDelegate(ByVal text As String)
Public LastLine As String
Public LastLineFormatted As String
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim LocalpathParent As String = Application.StartupPath() + "\MCserver"
'loads embed cmd
Me.AcceptButton = ExecuteButton
MyProcess = New Process
With MyProcess.StartInfo
.FileName = "CMD.EXE"
.UseShellExecute = False
.CreateNoWindow = True
.RedirectStandardInput = True
.RedirectStandardOutput = True
.RedirectStandardError = True
.WorkingDirectory = LocalpathParent
End With
MyProcess.Start()
MyProcess.BeginErrorReadLine()
MyProcess.BeginOutputReadLine()
AppendOutputText("Process Started at: " & MyProcess.StartTime.ToString)
'Resize with parent mdi container. Needs to be anchored & StartPosition = manual in properties
Me.WindowState = FormWindowState.Maximized
End Sub
Private Sub MyProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.ErrorDataReceived
AppendOutputText(vbCrLf & "Error: " & e.Data)
End Sub
Private Sub MyProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.OutputDataReceived
AppendOutputText(vbCrLf & e.Data)
'*****************************************
'Get Players and maybe other stuff as well
'*****************************************
LastLine = Me.OutputTextBox.Lines.Last
If Status.ServerStarted = True Then
If Me.LastLine.Contains(" joined the game") Then
LastLineFormatted = Me.LastLine
LastLineFormatted = LastLineFormatted.Replace(" joined the game", "")
'***THIS LINE BELOW WORKS IN FORM LOAD, BUT NOT HERE FOR SOME REASON???***
Status.txtPlayersList.Items.Add(LastLineFormatted)
MsgBox("add lastlineformatted")
ElseIf Me.LastLine.Contains(" left the game") Then
LastLineFormatted = Me.LastLine
LastLineFormatted = LastLineFormatted.Replace(" left the game", "")
Status.txtPlayersList.Items.Remove(LastLineFormatted)
End If
End If
End Sub
Private Sub ExecuteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExecuteButton.Click
MyProcess.StandardInput.WriteLine(InputTextBox.Text)
MyProcess.StandardInput.Flush()
InputTextBox.Text = ""
End Sub
Private Sub AppendOutputText(ByVal text As String)
If OutputTextBox.InvokeRequired Then
Dim myDelegate As New AppendOutputTextDelegate(AddressOf AppendOutputText)
Try
Me.Invoke(myDelegate, text)
Catch
End Try
Else
Try
OutputTextBox.AppendText(text)
Catch
End Try
End If
End Sub
End Class
EDIT: Below is the code I have for form1 per request
'code
Public Class Form1
Public Localpath As String
Public Downloadpath As String
Public LocalpathParent As String
'when this form is closing, send stop to console to make sure it has closed and saved
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Console.MyProcess.StandardInput.WriteLine("stop") 'send an EXIT command to the Command Prompt
Application.Exit()
End
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'load stuff in background n stuff
Me.Show()
Me.Focus()
Configure.Show()
Configure.Hide()
Status.Show()
Status.Hide()
Console.Show()
Console.Hide()
End Sub
'CONSOLE.form
Private Sub ConsoleToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ConsoleToolStripMenuItem1.Click
'Hide all forms
Status.Hide()
Configure.Hide()
'Shown Form that you want to load
Console.Opacity = 100
Console.Show()
WindowState = FormWindowState.Normal
Console.MdiParent = Me
Console.OutputTextBox.SelectionStart = Console.OutputTextBox.Text.Length
Console.OutputTextBox.ScrollToCaret()
End Sub
'STATUS.form
Private Sub StatusToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles StatusToolStripMenuItem1.Click
'hide all forms
Console.Hide()
Configure.Hide()
'Show Form that you want to load
Status.Opacity = 100
Status.Show()
WindowState = FormWindowState.Maximized
Configure.Size = Me.Size
Status.MdiParent = Me
End Sub
'CONFIGURE.form
Private Sub ConfigurationToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ConfigurationToolStripMenuItem1.Click
'hide all forms
Status.Hide()
Console.Hide()
'Show form that you want to load
Configure.Opacity = 100
Configure.Show()
WindowState = FormWindowState.Maximized
Configure.Size = Me.Size
Configure.MdiParent = Me
End Sub
End Class
'code
It seems that your original code to create an embeded CMD window was interfering with the code to update the listbox in another mdi child. After finding another way to embed a cmd console, and some fiddling around, It seems to be working Ok. I haven't been able to test pure server output yet though.
THere have been quite a few changes to the code that are too big to post here, but the Alternative embedded CMD is this.
Place this in general form declarations
'command prompt variables
Private strResults As String
Private intStop As Integer
Private swWriter As System.IO.StreamWriter
Friend thrdCMD As System.Threading.Thread
Private Delegate Sub cmdUpdate()
Private uFin As New cmdUpdate(AddressOf UpdateText)
Public WithEvents procCMDWin As New Process
This in your form_load Sub
thrdCMD = New System.Threading.Thread(AddressOf Prompt)
thrdCMD.IsBackground = True
thrdCMD.Start()
and these declarations within your form Class
Private Sub Prompt()
AddHandler procCMDWin.OutputDataReceived, AddressOf CMDOutput
AddHandler procCMDWin.ErrorDataReceived, AddressOf CMDOutput
procCMDWin.StartInfo.RedirectStandardOutput = True
procCMDWin.StartInfo.RedirectStandardInput = True
procCMDWin.StartInfo.CreateNoWindow = True
procCMDWin.StartInfo.UseShellExecute = False
procCMDWin.StartInfo.FileName = "cmd.exe"
procCMDWin.StartInfo.WorkingDirectory = LocalpathParent
procCMDWin.Start()
procCMDWin.BeginOutputReadLine()
swWriter = procCMDWin.StandardInput
Do Until (procCMDWin.HasExited)
Loop
procCMDWin.Dispose()
End Sub
Private Sub UpdateText()
OutputTextBox.Text += strResults
OutputTextBox.SelectionStart = OutputTextBox.TextLength - 1
InputTextBox.Focus()
intStop = OutputTextBox.SelectionStart
OutputTextBox.ScrollToCaret()
If OutputTextBox.Lines.Count > 2 Then
LastLine = OutputTextBox.Lines.ElementAt(OutputTextBox.Lines.Count - 2)
If Status.ServerStarted = True Then
'get element 1 of split
If LastLine.Contains(" joined the game") Then
LastLineFormatted = ExtractName(LastLine, " joined the game")
'If listlineformatted.contains(Players.allitems) then do
Status.txtPlayersList.Items.Add(LastLineFormatted)
Status.Show()
ElseIf Me.LastLine.Contains(" left the game") Then
LastLineFormatted = ExtractName(LastLine, " left the game")
'If listlineformatted.contains(Players.allitems) then do
Status.txtPlayersList.Items.Remove(LastLineFormatted)
MsgBox("remove lastlineformatted")
End If
End If
End If
End Sub
Private Function ExtractName(unformattedString As String, stringToRemove As String) As String
Dim temp As String = Split(unformattedString, "Server]")(1).ToString
ExtractName = temp.Replace(stringToRemove, "")
End Function
Private Sub CMDOutput(ByVal Sender As Object, ByVal OutputLine As DataReceivedEventArgs)
strResults = OutputLine.Data & Environment.NewLine
Invoke(uFin)
End Sub

STAThreadAttribute with SaveFileDialog VB.NET

I have an application to export ListView to Excel sheet , and im trying to do this in background but i have error in SaveFileDialog.showdialog().This is the error :
An exception of type 'System.Threading.ThreadStateException' occurred
in System.Windows.Forms.dll but was not handled in user code
Additional information: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process.
and this is my code :
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Public Sub saveExcelFile(ByVal FileName As String)
Try
Dim xls As New Excel.Application
Dim sheet As Excel.Worksheet
Dim i As Integer
xls.Workbooks.Add()
sheet = xls.ActiveWorkbook.ActiveSheet
Dim row As Integer = 1
Dim col As Integer = 1
For i = 0 To Me.ListView1.Columns.Count - 1
sheet.Cells(1, i + 1) = Me.ListView1.Columns(i).Text
Next
For i = 0 To Me.ListView1.Items.Count - 1
For j = 0 To Me.ListView1.Items(i).SubItems.Count - 1
sheet.Cells(i + 2, j + 1) = Me.ListView1.Items(i).SubItems(j).Text
Next
Next
row += 1
col = 1
' for the header
sheet.Rows(1).Font.Name = "Cooper Black"
sheet.Rows(1).Font.size = 12
sheet.Rows(1).HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter
Dim mycol As System.Drawing.Color = System.Drawing.ColorTranslator.FromHtml("#148cf7")
sheet.Rows(1).Font.color = mycol
' for all the sheet without header
sheet.Range("a2", "z1000").Font.Name = "Arial"
sheet.Range("a2", "z1000").Font.Size = 13
sheet.Range("a2", "z1000").HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter
sheet.Range("A1:X1").EntireColumn.AutoFit()
sheet.Range("A1:X1").EntireRow.AutoFit()
xls.ActiveWorkbook.SaveAs(FileName)
xls.Workbooks.Close()
xls.Quit()
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
Dim saveFileDialog1 As New SaveFileDialog
saveFileDialog1.Filter = "Excel File|*.xlsx"
saveFileDialog1.Title = "Save an Excel File"
saveFileDialog1.ShowDialog()
If saveFileDialog1.FileName <> "" Then
saveExcelFile(saveFileDialog1.FileName)
End If
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
MsgBox("done")
End Sub
You could move everything concerning SaveFileDialog1 to Button3_Click and store the filename in a Private variable, so it can be used later in BackgroundWorker1_DoWork.
Private _filename As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
SaveFileDialog1.Title = "Save Excel File"
SaveFileDialog1.Filter = "Excel files (*.xls)|*.xls|Excel Files (*.xlsx)|*.xslx"
SaveFileDialog1.ShowDialog()
'exit if no file selected
If SaveFileDialog1.FileName = "" Then
Exit Sub
End If
_filename = SaveFileDialog1.FileName
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
...
book.SaveAs(_filename)
...
End Sub
i put this code in load form and everything is perfect:
Control.CheckForIllegalCrossThreadCalls = False