vb.NET You are not allowed to perform an operation across different threads - vb.net

I am running code to read text from pdf files and than create a WordCloud. To inform the user the process is on going I add a BackgroundWorker to my form that shows an image saying Loading. I get an error for operating across different threads.
Private Sub ButtonCreate_Click(sender As Object, e As EventArgs) Handles ButtonCreate.Click
bTextEmpty = False
ListView1.Items.Clear()
ResultPictureBox.Image = Nothing
If ListBox1.SelectedIndex > -1 Then
For Each Item As Object In ListBox1.SelectedItems
Dim ItemSelected = CType(Item("Path"), String)
Dim myTempFile As Boolean = File.Exists(ItemSelected + "\Words.txt")
If myTempFile = False Then
'when we load the form we first call the code to count words in all files in a directory
'lets check if the folder exists
If (Not System.IO.Directory.Exists(ItemSelected)) Then
Dim unused = MsgBox("The archive " + ItemSelected.Substring(ItemSelected.Length - 5, Length) + " was not found",, Title)
Exit Sub
Else
Call CreateWordList(ItemSelected)
End If
End If
'if the words file is empty we cant create a cloud so exit the sub
If bTextEmpty = True Then Exit Sub
'then we fill the wordcloud and Listview from the created textfile
Call CreateMyCloud(ItemSelected + "\Words.txt")
Next
Else
Dim unused = MsgBox("You have to choose an Archive to create the Word Cloud",, Title)
End If
Size = New Drawing.Size(1400, 800)
End Sub
I put above code in a Private Sub and called it from my BackgroundWorker. The error occured at this line: If ListBox1.SelectedIndex > -1 Then
After trying the suggested code I get the same error again:
Public Sub CreateMyCloud(ByVal sourcePDF As String)
Dim WordsFreqList As New List(Of WordsFrequencies)
For Each line As String In File.ReadLines(sourcePDF)
Dim splitText As String() = line.Split(","c)
If splitText IsNot Nothing AndAlso splitText.Length = 2 Then
Dim wordFrq As New WordsFrequencies
Dim freq As Integer
wordFrq.Word = splitText(0)
wordFrq.Frequency = If(Integer.TryParse(splitText(1), freq), freq, 0)
WordsFreqList.Add(wordFrq)
End If
Next
If WordsFreqList.Count > 0 Then
' Order the list based on the Frequency
WordsFreqList = WordsFreqList.OrderByDescending(Function(w) w.Frequency).ToList
' Add the sorted items to the listview
WordsFreqList.ForEach(Sub(wf)
error -> ListView1.Items.Add(New ListViewItem(New String() {wf.Word, wf.Frequency.ToString}, 0))
End Sub)
End If
Dim wc As WordCloudGen = New WordCloudGen(600, 400)
Dim i As Image = wc.Draw(WordsFreqList.Select(Function(wf) wf.Word).ToList, WordsFreqList.Select(Function(wf) wf.Frequency).ToList)
ResultPictureBox.Image = i
End Sub

Should look something more like:
Private Sub ButtonCreate_Click(sender As Object, e As EventArgs) Handles ButtonCreate.Click
If ListBox1.SelectedItems.Count > 0 Then
Dim data As New List(Of Object)
For Each Item As Object In ListBox1.SelectedItems
data.Add(Item)
Next
bTextEmpty = False
ListView1.Items.Clear()
ResultPictureBox.Image = Nothing
BackgroundWorker1.RunWorkerAsync(data)
Else
MessageBox.Show("You have to choose an Archive to create the Word Cloud",, Title)
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim data As List(Of Object) = DirectCast(e.Argument, List(Of Object))
For Each Item As Object In data
Dim ItemSelected = CType(Item("Path"), String)
Dim myTempFile As Boolean = File.Exists(ItemSelected + "\Words.txt")
If myTempFile = False Then
'when we load the form we first call the code to count words in all files in a directory
'lets check if the folder exists
If (Not System.IO.Directory.Exists(ItemSelected)) Then
MessageBox.Show("The archive " + ItemSelected.Substring(ItemSelected.Length - 5, Length) + " was not found",, Title)
Exit Sub
Else
Call CreateWordList(ItemSelected)
End If
End If
'if the words file is empty we cant create a cloud so exit the sub
If bTextEmpty = True Then Exit Sub
'then we fill the wordcloud and Listview from the created textfile
Call CreateMyCloud(ItemSelected + "\Words.txt")
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Size = New Drawing.Size(1400, 800)
End Sub

To fix the error in your second, edited post:
WordsFreqList.ForEach(Sub(wf)
ListView1.Invoke(Sub()
ListView1.Items.Add(New ListViewItem(New String() {wf.Word, wf.Frequency.ToString}, 0))
End Sub)
End Sub)

You cannot simply access controls outside of the current thread. You first need to call the Invoke method on the target control and then pass a delegate containing the instructions intended to modify the control outside of the current thread. See this article on MSDN on how to do this: https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls?view=netframeworkdesktop-4.8

Related

Read and write below a precise cell in a CSV

I'm stuck on a basic problem. What I want is to parse through a CSV in order to compare some string and write below if I find it.
Precisely, I have a programe where I can drag and drop some button, when I drop this button I want to save it's new location on the first empty cells below the corresponding column.
Here's a sample of my CSV :
So I substring the .x/.y from my CSV and compare the name from the drop button with each cell with the help of textFieldParser. It seems to work my loop stopped when it find an equal expression.
But here's the problem I don't know how to say to my program to write below it. The first reason I can figured it out is because my parser go until the endOfData and I want it to go until the endOfDat + one row.
The second one is because I don't know if I can use a fieldwriter into textFieldParser, I mean I tried to create a variable with row+1 and write below but nothing happen when I use fileWriter.
now a sample of my code :
Private Sub manageCsv(ByVal sender As Button)
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("..\..\Pic\csvPic.csv")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
Dim rowPlusOne As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
rowPlusUn = MyReader.ReadFields()
Dim currentField As String
Dim str As String = btnSender.Name.Substring(3)
Dim nameDelimited As String
Dim x As Integer
For Each currentField In currentRow
''Search the corresponding field''
x = InStr(currentField, ".")
If Not (currentField.Equals("imagefile")) Then ''imagefile is the first index of my csv''
nameDelimited = currentField.Substring(0, x) ''substr the extension''
If nameDelimited.Equals(str) Then
writeCsv("..\..\Image\csvPic.csv", nameDelimited, ",")
''Ofc the "+1" does not work but that was the idea''
currentRow(+1) = lblImgName.Text
currentRow(+1) = btnSender.Location.ToString
Exit For
End If
End If
Next
Catch ex As _
Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
End Try
End While
End Using
End Sub
I hope it's clear enough, if not i'll try to elaborate more. Thanks for your help
Show your teacher that there are better ways to do this with a simple text file. The file will only exist if buttons have been moved before in the application. See in line comments.
Private ButtonLocation As New Dictionary(Of Button, Point)
Private MouseIsDown As Boolean
Private ptX, ptY As Integer 'Starting point of mouse relative to the button
Private btn As Button 'The button being moved
Private ButtonPath As String = "C:\Users\maryo\Desktop\Code\DroppedButtons.txt"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Reposition the buttons to where they were dropped in the previous session.
If File.Exists(ButtonPath) Then
Dim lines = File.ReadAllLines(ButtonPath) 'returns an array of strings (each line)
For Each line In lines 'loop though each line in the file
Dim fields = line.Split(","c) 'The three values on the line are separated by a comma
Dim b = DirectCast(Controls(fields(0)), Button) 'Change the string Button.Name
'to an actual Button object by finding it in the controls collection
'Set the location with the next 2 values on the line
b.Location = New Point(CInt(fields(1)), CInt(fields(2)))
'Add the Button and Location to the list
ButtonLocation.Add(b, b.Location)
Next
End If
End Sub
'These three Event procedures are the normal code to Drag and Drop a control
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown, Button2.MouseDown
btn = DirectCast(sender, Button)
ptX = e.Location.X
ptY = e.Location.Y
MouseIsDown = True
End Sub
Private Sub Button_MouseMove(sender As Object, e As MouseEventArgs) Handles Button1.MouseMove, Button2.MouseMove
If MouseIsDown Then
'e.X and e.Y are the coordinates of the Mouse relative to the control (the Button)
'not the Form or the Screen.
btn.Location = New Point(btn.Location.X + e.X - ptX, btn.Location.Y + e.Y - ptY)
End If
End Sub
Private Sub Button_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp, Button2.MouseUp
MouseIsDown = False
'When we drop the button with the MouseUp event we record the new location in the list
RecordButtonLocation(btn, btn.Location)
btn = Nothing
End Sub
Private Sub RecordButtonLocation(Sender As Button, Location As Point)
'Check if the Button is already in the list
If ButtonLocation.ContainsKey(Sender) Then
'Record its new location
ButtonLocation.Item(Sender) = Location
Else
'If it is not in the list add it.
ButtonLocation.Add(Sender, Location)
End If
End Sub
Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
SaveDictionary()
End Sub
Private Sub SaveDictionary()
If ButtonLocation.Count > 0 Then
'If there is anything in the list we will create or overwrite the file
Dim sb As New StringBuilder
For Each kv As KeyValuePair(Of Button, Point) In ButtonLocation
sb.AppendLine($"{kv.Key.Name},{kv.Value.X},{kv.Value.Y}")
Next
File.WriteAllText(ButtonPath, sb.ToString)
End If
End Sub

vb.net save textbox values for later use

I use a textbox in my form to search for words in pdf files. I want to save these search words somewhere for later use. So when the user types a letter in the textbox there will be a pulldown with previous searched words. Something like windows does in Explorer.
Does anyone have an example or is someone familiar with this?
You can store and retrieve a list of search words in an application settings entry of type StringCollection as the data source of the TextBox.AutoCompleteCustomSource property.
Add new entry
Select YourAppName Properties from the Project menu.
Select the Settings tab.
Add new entry in the Name column, say: SearchWords.
From the Type column, select System.Collections.Specialized.StringCollection.
Close the dialog and save.
Retrieve the search words
In the Form's constructor or Load event, say you have a search TextBox named txtSearch:
' +
Imports System.Linq
Imports System.Collections.Specialized
Private Sub YourForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If My.Settings.SearchWords Is Nothing Then
My.Settings.SearchWords = New StringCollection
End If
Dim acc As New AutoCompleteStringCollection
acc.AddRange(My.Settings.SearchWords.Cast(Of String).ToArray())
txtSearch.AutoCompleteMode = AutoCompleteMode.Suggest
txtSearch.AutoCompleteSource = AutoCompleteSource.CustomSource
txtSearch.AutoCompleteCustomSource = acc
End Sub
Update the collection
You need to add the new words whenever you perform a search:
' When you click a search button...
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
AddSearchWord()
End Sub
' If you call the search routine when you press the Enter key...
Private Sub txtSearch_KeyDown(sender As Object, e As KeyEventArgs) Handles txtSearch.KeyDown
If e.KeyCode = Keys.Enter Then
AddSearchWord()
End If
End Sub
' Update the collection...
Private Sub AddSearchWord()
If txtSearch.Text.Trim.Length = 0 Then Return
If Not txtSearch.AutoCompleteCustomSource.Contains(txtSearch.Text) Then
If txtSearch.AutoCompleteCustomSource.Count > 10 Then
txtSearch.AutoCompleteCustomSource.RemoveAt(
txtSearch.AutoCompleteCustomSource.Count - 1)
End If
txtSearch.AutoCompleteCustomSource.Insert(0, txtSearch.Text)
End If
End Sub
Save the collection
Update the SearchWord string collection when you close the Form:
Private Sub YourForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
My.Settings.SearchWords = New StringCollection
My.Settings.SearchWords.AddRange(txtSearch.AutoCompleteCustomSource.Cast(Of String).ToArray)
My.Settings.Save()
End Sub
Demo
I found some code Saving text box values to a file to load again that I changed to my needs. It saves the content of my ComboBox1 to a textfile when I click my Submit button. When I load the form the textfile is read and loaded into the ComboBox1 as previous used searches.
'now save the search word to our textfile
PresetName = TextBoxFreeText.Text
If PresetName <> "" Then
TextBoxFreeText.Items.Add(PresetName)
Call SaveData(PresetName)
End If
The code to load the saved values:
Private Sub ReadData()
If My.Computer.FileSystem.FileExists(FilePath) = True Then
myReader = New StreamReader(FilePath)
Dim myText = myReader.ReadLine
While myText IsNot Nothing
listPreset.Add(myText)
myText = myReader.ReadLine
End While
myReader.Close()
'Add Preset Names to ComboBox
If listPreset.Count > 0 Then
Dim PresetName As String
Dim index As Integer
For i = 0 To listPreset.Count - 1
index = listPreset.Item(i).IndexOf(",")
PresetName = Mid(listPreset.Item(i), 1, index)
TextBoxFreeText.Items.Add(PresetName)
Next
End If
End If
End Sub
The code to save the content of ComboBox1
Private Sub SaveData(ByVal PresetName As String)
Dim FileString As String = PresetName & ","
'Build File String
FileString &= TextBoxFreeText.Text & ","
listPreset.Add(FileString)
myWriter = New StreamWriter(FilePath)
For i = 0 To listPreset.Count - 1
myWriter.WriteLine(listPreset.Item(i))
Next
myWriter.Close()
End Sub
There are still two things I want to change. I will ask in a new question.
prevent duplicate search string to be entered in the textfile.
set a maximum to the search string loaded in ComboBox1 (maybe 10 words)

VB.Net populating text boxes from text file

I'm creating an inventory management system where the data is stored in a text file. I'm able to save data to the text file, however on the tracker screen it should show current inventory such as: Manufacturer, Processor, Video, Form, RAM, etc. However, all my text boxes remain blank and I'm not sure why. It's not reading properly or updating the text.
frmTracker.vb
Private Sub txtManufacturer_TextChanged(sender As Object, e As EventArgs) Handles txtManufacturer.TextChanged
Dim objMyStreamReader = System.IO.File.OpenText("inventory.txt")
Dim strInventory = objMyStreamReader.ReadLine()
objMyStreamReader.Close()
txtManufacturer.AppendText(strInventory)
End Sub
This is how I'm currently saving the data to the text file.
frmItemEntry.vb
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim objMyStreamReader As System.IO.StreamReader
Dim objMyStreamWriter As System.IO.StreamWriter = System.IO.File.CreateText("inventory.txt")
Dim strInventory As String
objMyStreamWriter.WriteLine(txtManufacturerEntry.Text)
objMyStreamWriter.WriteLine(txtProcessorEntry.Text)
objMyStreamWriter.WriteLine(txtVideoEntry.Text)
objMyStreamWriter.WriteLine(txtFormEntry.Text)
objMyStreamWriter.WriteLine(txtRamEntry.Text)
objMyStreamWriter.WriteLine(txtVramEntry.Text)
objMyStreamWriter.WriteLine(txtHdEntry.Text)
objMyStreamWriter.WriteLine(chkWirelessEntry.CheckState)
objMyStreamWriter.Close()
Me.Close()
End Sub
Example from inventory.txt
Dell
i5
Nvidia
Desktop
8
4
600
0
To be honest, controls should never be used as the primary store for your data in a program. You should really be creating a class and a list of that class to store your data.
You can then read your data into the list from your file, and then, display it from there in your form.
There are several ways of navigating through the data and saving updates. The suggestion below uses buttons for next item and previous item, and a button to save update the file.
It's all pretty self explanatory, but if there's something your not sure about, please have a google and learn something new :-D
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ReadDataFile()
DisplayItem(0)
End Sub
Private Class InventoryItem
Public Property Manufacturer As String
Public Property Processor As String
Public Property Video As String
Public Property FormFactor As String
Public Property Ram As String
Public Property VRam As String
Public Property Hd As String
Public Property Wireless As CheckState
Public Sub New()
Manufacturer = ""
Processor = ""
Video = ""
FormFactor = ""
Ram = ""
VRam = ""
Hd = ""
Wireless = CheckState.Unchecked
End Sub
End Class
Dim Inventory As New List(Of InventoryItem)
Dim currentItemIndex As Integer
Private Sub ReadDataFile()
Using objMyStreamReader As New StreamReader("k:\inventory.txt")
Do Until objMyStreamReader.EndOfStream
Dim newItem As New InventoryItem
newItem.Manufacturer = objMyStreamReader.ReadLine()
newItem.Processor = objMyStreamReader.ReadLine()
newItem.Video = objMyStreamReader.ReadLine()
newItem.FormFactor = objMyStreamReader.ReadLine()
newItem.Ram = objMyStreamReader.ReadLine()
newItem.VRam = objMyStreamReader.ReadLine()
newItem.Hd = objMyStreamReader.ReadLine()
Dim wirelessValue As String = objMyStreamReader.ReadLine()
If wirelessValue = "0" Then
newItem.Wireless = CheckState.Unchecked
ElseIf wirelessValue = "1" Then
newItem.Wireless = CheckState.Checked
End If
Inventory.Add(newItem)
Loop
End Using
End Sub
Private Sub SaveDataFile()
Using objMyStreamWriter As New System.IO.StreamWriter("k:\inventory.txt", False)
For Each item As InventoryItem In Inventory
objMyStreamWriter.WriteLine(item.Manufacturer)
objMyStreamWriter.WriteLine(item.Processor)
objMyStreamWriter.WriteLine(item.Video)
objMyStreamWriter.WriteLine(item.FormFactor)
objMyStreamWriter.WriteLine(item.Ram)
objMyStreamWriter.WriteLine(item.VRam)
objMyStreamWriter.WriteLine(item.Hd)
If item.Wireless = CheckState.Checked Then
objMyStreamWriter.WriteLine("1")
Else
objMyStreamWriter.WriteLine(0)
End If
Next
End Using
End Sub
Private Sub DisplayItem(index As Integer)
With Inventory(index)
txtManufacturerEntry.Text = .Manufacturer
txtProcessorEntry.Text = .Processor
txtVideoEntry.Text = .Video
txtFormEntry.Text = .FormFactor
txtRamEntry.Text = .Ram
txtVramEntry.Text = .VRam
txtHdEntry.Text = .Hd
chkWirelessEntry.CheckState = .Wireless
End With
End Sub
Private Sub BtnUpdateItem_Click(sender As Object, e As EventArgs) Handles BtnUpdateItem.Click
With Inventory(currentItemIndex)
.Manufacturer = txtManufacturerEntry.Text
.Processor = txtProcessorEntry.Text
.Video = txtVideoEntry.Text
.FormFactor = txtFormEntry.Text
.Ram = txtRamEntry.Text
.VRam = txtVramEntry.Text
.Hd = txtHdEntry.Text
.Wireless = chkWirelessEntry.CheckState
End With
SaveDataFile()
End Sub
Private Sub BtnPreviousItem_Click(sender As Object, e As EventArgs) Handles BtnPreviousItem.Click
If currentItemIndex > 0 Then
currentItemIndex -= 1
DisplayItem(currentItemIndex)
End If
End Sub
Private Sub BtnNextItem_Click(sender As Object, e As EventArgs) Handles BtnNextItem.Click
If currentItemIndex < Inventory.Count - 1 Then
currentItemIndex -= 1
DisplayItem(currentItemIndex)
End If
End Sub
First change the format of your text file.
Dell,i5,Nvidia,Desktop,8,2,600,True
Acer,i7,Intel,Desktop,16,4,1GB,True
HP,Pentium,Diamond Viper,Desktop,4,2,200,False
Surface Pro,i7,Intel,Laptop,8,2,500,True
Each line is a record and each field in the record is separated by a comma (no spaces so we don't have to .Trim in code) (a space within a field is fine, notice Surface Pro).
Now it is easier to read the file in code.
This solution uses a BindingSource and DataBindings. This simplifies Navigation and editing and saving the data.
Public Class Form5
Private bs As BindingSource
Private dt As New DataTable
#Region "Set Up the Form"
Private Sub Form5_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddColumnsToDataTable()
FillDataTable()
AddDataBindings()
End Sub
Private Sub AddColumnsToDataTable()
'Prepare the DataTable to hold data
dt.Columns.Add("Manufacturer", GetType(String))
dt.Columns.Add("Processor", GetType(String))
dt.Columns.Add("Video", GetType(String))
dt.Columns.Add("Form", GetType(String))
dt.Columns.Add("RAM", GetType(String))
dt.Columns.Add("VRAM", GetType(String))
dt.Columns.Add("HD", GetType(String))
dt.Columns.Add("Wireless", GetType(Boolean))
End Sub
Private Sub FillDataTable()
'ReadAllLines returns an array of the lines in a text file
'inventory.txt is stored in the bin\Debug folder of your project
'This is the current directory so it does not require a full path.
Dim lines = File.ReadAllLines("inventory.txt")
'Now it is easy to split each line into fields by using the comma
For Each line As String In lines
'Split returns an array of strings with the value of each field
Dim items = line.Split(","c)
'Each item in the array can be added as a field to the DataTable row
dt.Rows.Add(items(0), items(1), items(2), items(3), items(4), items(5), items(6), CBool(items(7)))
'Notice that the last element is changed from a string to a boolean. This is
'the Wireless field which is bound to the check box. The string "True" or "False" is
'changed to a Boolean so it can be used as the .Checked property (see bindings)
Next
End Sub
Private Sub AddDataBindings()
'Create a new instance of the BindingSource class
bs = New BindingSource()
'Set the DataSource to the DataTable we just filled
bs.DataSource = dt
'Now you can set the bindings of each control
'The .Add method takes (Name of Property to Bind, the BindingSource to use, The Field name
'from the DataTable.
txtForm.DataBindings.Add("Text", bs, "Form")
txtHd.DataBindings.Add("Text", bs, "HD")
txtManufacturer.DataBindings.Add("Text", bs, "Manufacturer")
txtProcessor.DataBindings.Add("Text", bs, "Processor")
txtRam.DataBindings.Add("Text", bs, "RAM")
txtVideo.DataBindings.Add("Text", bs, "Video")
txtVram.DataBindings.Add("Text", bs, "VRAM")
'Notice on the CheckBox we are using the Checked property.
chkWireless.DataBindings.Add("Checked", bs, "Wireless")
End Sub
#End Region
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
'Add a blank row to the DataTable
'A Boolean is like a number, a String can be Nothing but a Boolean must
'have a value so we pass in False.
dt.Rows.Add(Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, False)
'Find the position of the last row
Dim i As Integer = bs.Count - 1
'Move to the new empty row
bs.Position = i
End Sub
#Region "Navigation Code"
Private Sub btnPrevious_Click(sender As Object, e As EventArgs) Handles btnPrevious.Click
'The binding source Position determins where in the data you are
'It starts at zero
If bs.Position = 0 Then
MessageBox.Show("This is the first item.")
Return 'This exits the sub, you can use Exit Sub in vb
'but Return is common in other languages so it is good to learn
Else
'As the position of the BindingSource changes the boud TextBoxes
'change their data.
bs.Position = bs.Position - 1
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
' If you are not at the end of the list, move to the next item
' in the BindingSource.
If bs.Position + 1 < bs.Count Then
bs.MoveNext()
' Otherwise, move back to the first item.
Else
bs.MoveFirst()
End If
End Sub
#End Region
#Region "Save the Data"
Private Sub SaveDataTable()
'Resave the whole file if this was a real app you would use a database
Dim sb As New StringBuilder
'A string builder keeps the code from creating lots of new strings
'Strings are immutable (can't be changed) so every time you think you are
'changing a string, you are actually creating a new one.
'The string builder is mutable (changable)
For Each row As DataRow In dt.Rows
'The ItemsArray returns an array of objects containing all the
'values in each column of the data table.
Dim rowValues = row.ItemArray
'This is a bit of Linq magic that turns the values (objects) into strings
'Underneath it is performing a For loop on each object in the array
Dim strRowValues = From o In rowValues
Select Convert.ToString(o)
'Now that we have strings we can use the String.Join with the comma
'to get the format of the text file
sb.AppendLine(String.Join(",", strRowValues))
Next
'Finally we change the StringBuilder to a real String
'The inventory.txt is stored in the bin\Debug directory so it is current directory
'no additional path required
File.WriteAllText("inventory.txt", sb.ToString)
End Sub
Private Sub Form5_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
'Because our binding is two-way any additions or changes to the text
'in the text boxes or check box are reflected in the DataTable.
SaveDataTable()
End Sub
#End Region
End Class
Once you remove the comments, there is really very little code here. The #Region...#End Region tags make it easy to collapse code sections you are not working on and find areas quickly.

Visual Basic Sequential Access Files

I've been working on this assignment for quite awhile, but I'm practically ripping my hair out. Before anyone jumps the gun and says I'm looking for a free handout on the assignment, please note, I've done 90% of the assignment! The program has 4 commercials in a list, you choose which one to vote for and it saves your vote and tallies it. As it tallies it in the program, it also saves it into a file. The next time you open the file, you can hit "Display vote" and it reads the file and re-tally's everything for the user.
Here's what the program looks like, at least what I have done. My issue is that when I hit display votes, nothing happens. It doesn't read in anything from the file. I tested using a message box for it to see if it displays anything from the file, and it does infact display the first item from the project. Anyone have any ideas?!
Public Class frmMain
Dim intVotes(3) As Integer
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lstCom.Items.Add("Budweiser")
lstCom.Items.Add("FedEx")
lstCom.Items.Add("E*Trade")
lstCom.Items.Add("Pepsi")
lstCom.SelectedIndex = 0
End Sub
Private Sub btnSaveVote_Click(sender As Object, e As EventArgs) Handles btnSaveVote.Click
Dim outFile As IO.StreamWriter
Dim intSub As Integer
intSub = lstCom.SelectedIndex
If intSub <= intVotes.GetUpperBound(0) Then
intVotes(intSub) += 1
If IO.File.Exists("CallerVotes.txt") Then
outFile = IO.File.CreateText("CallerVotes.txt")
If lstCom.SelectedIndex = 0 Then
outFile.WriteLine("Budweiser")
ElseIf lstCom.SelectedIndex = 1 Then
outFile.WriteLine("FedEx")
ElseIf lstCom.SelectedIndex = 2 Then
outFile.WriteLine("E*TRADE")
ElseIf lstCom.SelectedIndex = 3 Then
outFile.WriteLine("Pepsi")
End If
outFile.Close()
End If
End If
lblBud.Text = intVotes(0).ToString
lblFed.Text = intVotes(1).ToString
lblET.Text = intVotes(2).ToString
lblPep.Text = intVotes(3).ToString
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstCom.SelectedIndexChanged
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Private Sub btnDisplayVote_Click(sender As Object, e As EventArgs) Handles btnDisplayVote.Click
Dim inFile As IO.StreamReader
Dim strText As String
If IO.File.Exists("CallerVotes.txt") Then
inFile = IO.File.OpenText("CallerVotes.txt")
Do Until inFile.Peek = -1
strText = inFile.ReadLine
If strText = "Budweiser" Then
intVotes(0) += 1
ElseIf strText = "FedEx" Then
intVotes(1) += 1
ElseIf strText = "E*TRADE" Then
intVotes(2) += 1
ElseIf strText = "Pepsi" Then
intVotes(3) += 1
End If
Loop
inFile.Close()
End If
End Sub
End Class
If you look at your file I think you will see that you have only one entry. You are overwriting the file each time you click the save button by using the CreateText method.
from MSDN(emphasis mine)
This method is equivalent to the StreamWriter(String, Boolean) constructor overload with the append parameter set to false. If the file specified by path does not exist, it is created. If the file does exist, its contents are overwritten.
try using the AppendText method instead.
i.e.
If IO.File.Exists("CallerVotes.txt") Then
outFile = IO.File.AppendText("CallerVotes.txt")
You will also need to assign the values that you read in to the appropriate labels per DeanOC's answer.
I think that your problem is that you are not assigning the values from the intVotes array to the labels. At the end of btnDisplayVote_Click try adding
lblBud.Text = intVotes(0).ToString
lblFed.Text = intVotes(1).ToString
lblET.Text = intVotes(2).ToString
lblPep.Text = intVotes(3).ToString

vb.net Find Form

In the Windows, the native Notepad program has a find form. Basically When the user types and hits 'Find Next', the program proceeds to find the text while keeping the focus on the Find form. This way the user can keep hitting the 'Enter' key or the button and still have the text highlighted while the form is focused.
My problem is that I have a different form for the "Search" feature and whenever the user hits "Enter" the text is found and the focus is set on the TextBox but when the user hits "Enter" again, the text gets edited because of the focus.
Currently, I'm using Regex to do this and I am using a WPF TextBox using HostElement:
Private Function GetRegExpression() As Regex
Dim result As Regex
Dim regExString As [String]
regExString = txtbx_Find.Text
If matchCaseCheckBox.Checked Then
result = New Regex(regExString)
Else
result = New Regex(regExString, RegexOptions.IgnoreCase)
End If
Return result
End Function
Private Sub FindText()
''
Dim WpfTest1 As New SpellPad.Tb
Dim ElementHost1 As System.Windows.Forms.Integration.ElementHost = frm_Menu.Controls("ElementHost1")
Dim TheTextBox As System.Windows.Controls.TextBox = CType(ElementHost1.Child, Tb).ctrl_TextBox
''
If isFirstFind Then
regex = GetRegExpression()
match = regex.Match(TheTextBox.Text)
isFirstFind = False
Else
match = regex.Match(TheTextBox.Text, match.Index + 1)
End If
If match.Success Then
Dim row As Integer = TheTextBox.GetLineIndexFromCharacterIndex(TheTextBox.CaretIndex)
MoveCaretToLine(TheTextBox, row + 1)
TheTextBox.SelectionStart = match.Index
TheTextBox.SelectionLength = match.Length
TheTextBox.Focus()
Me.Focus()
Else
MessageBox.Show([String].Format("Cannot find ""{0}"" ", txtbx_Find.Text), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information)
isFirstFind = True
End If
End Sub
Private Sub btn_FindNext_Click(sender As Object, e As EventArgs) Handles btn_FindNext.Click
''
Dim WpfTest1 As New SpellPad.Tb
Dim ElementHost1 As System.Windows.Forms.Integration.ElementHost = frm_Menu.Controls("ElementHost1")
Dim TheTextBox As System.Windows.Controls.TextBox = CType(ElementHost1.Child, Tb).ctrl_TextBox
''
FindText()
'theTextBox.Focus()
End Sub
I want it to be just like Notepad where the user hits "Enter" and keeps focus on the Find Form while selecting the text. How can this be achieved?
I think you should catch "keyup" event of your form like this :
Class MainWindow
Private Sub Window_KeyUp(sender As System.Object, e As System.Windows.Input.KeyEventArgs) Handles MyBase.KeyUp
If e.Key = Key.Enter Then
FindNext()
End If
End Sub
Private Sub btn_FindNext_Click(sender As Object, e As EventArgs) Handles btn_FindNext.Click
FindText()
End Sub
Private Sub FindNext()
''
Dim WpfTest1 As New SpellPad.Tb
Dim ElementHost1 As System.Windows.Forms.Integration.ElementHost = frm_Menu.Controls("ElementHost1")
Dim TheTextBox As System.Windows.Controls.TextBox = CType(ElementHost1.Child, Tb).ctrl_TextBox
''
FindText()
'theTextBox.Focus()
End Sub
End Class