Pause a for loop to await user interaction - vb.net

I'm having a bit of a problem figuring out how to pause a for...next loop to await user interaction. I'm comparing the hashes of different files in a for...next loop and if they are different, I want to pause the loop until the user decided which file to keep.
Here's my code, so i hope you see what I'm trying to do.
For i = 0 To ListBox1.Items.Count - 1
If GetCRC32(ListBox1.Items.Item(i)) = GetCRC32(ListBox2.Items.Item(i)) Then
log("same")
Else
Dim v1 As String = ListBox1.Items.Item(i)
Dim v2 As String = ListBox2.Items.Item(i)
Dim f1 As New FileInfo(v1)
Dim f2 As New FileInfo(v2)
Dim c As String
If f1.LastWriteTime > f2.LastWriteTime Then
c = v1
Else
c = v2
End If
RichTextBox1.Text = v1 & " and " & v2 & " seem to be different." & vbCrLf & _
"Last changed:" & c
End If
Next
The user-interaction is via two buttons, which I have no code for yet...

Why dont you use Form.ShowDialog in the loop.
Stops execution of the loop and you can ask user whatever question you need.

Related

Reading ListView from BackgroundWorker

I've tried doing some searchs but for the life of me I don't seem to be able to find the answer, or a suggested solution that works. Its probably my understanding, but hopefully asking my own question will give me an answer that works :o)
I have a Windows Form Application which consists of one item, ListView1
This ListView has items added to it from a file via a Drag / Drop which is done on the main UI Thread, no background worker, it consists of around 1500 rows.
I'm trying to get a background worker now to read this ListView, but I'm getting a Cross Threading error as ListView1 was not created on the same thread.
The error comes on the simplest of pieces of code, but I don't seem to be able to think of a way around it or implementing an invoke etc.
For i = 0 To Me.ListView1.Items.Count - 1
ValueStatement = ValueStatement & "(" & Me.ListView1.Items(i).SubItems(0).Text
If i = Me.ListView1.Items.Count - 1 Or counter = 500 Then
CommaTerminate = ";"
Else
CommaTerminate = ","
End If
For y = 0 To Me.ListView1.Columns.Count - 1
ValueStatement = ValueStatement & "'" & Me.ListView1.Items(i).SubItems(y).Text & "'"
If y = Me.ListView1.Columns.Count - 1 Then
ValueStatement = ValueStatement & ")"
Else
ValueStatement = ValueStatement & ","
End If
Next
ValueStatement = ValueStatement & CommaTerminate & vbNewLine
If counter = 500 Then
SQLStatement = "INSERT INTO RAW_CLI_DATA_" & GlobalVariables.CDR_Company & " VALUES " & vbNewLine & ValueStatement
GenericDatabaseRequest(SQLStatement, "Loading RAW table with data..")
counter = 0
ValueStatement = ""
End If
counter = counter + 1
Next
The error comes on the line ValueStatement = ValueStatement & "(" & Me.ListView1.Items(i).SubItems(0).Text
Thanks for any help!
It sounds like you went down the wrong road early on. The ListView is supremely illsuited for database ops:
Everything is contained as String which means somewhere you will have code to convert it to other types
It does not support databinding which means you have to manually create rows...
... then later iterate them to fish the data back out.
A DataGridView and DataTable would be simpler: When the user enters data into the control and it would be stored in the table and as the proper type. Setting the DataTable as the Datasource, the DataGridView would create the display (rows and columns) for you.
Some of the time it takes will be consumed by SQLite to perform the INSERT, but it also looks like you are spending a lot of time iterating and concatenating SQL. It's usually better to work with the data than the user's View of it anyway, so extract and pass the data to the worker.
First, suck the data out of the ListView into a String()() container:
Dim data = lv.Items.
Cast(Of ListViewItem).
Select(Function(s) New String() {s.SubItems(0).Text,
s.SubItems(1).Text,
s.SubItems(2).Text}).
ToArray()
Then pass it to the BackGroundWorker:
bgw.RunWorkerAsync(data)
The DoWork Event:
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
' unbox the data
Dim dataToInsert = CType(e.Argument, String()())
For n As Int32 = 0 To 2
Console.WriteLine("[{0}], [{1}], [{2}]", dataToInsert(n)(0),
dataToInsert(n)(1),
dataToInsert(n)(2))
Next
End Sub
Results:
[Patient Tempest], [Lorem ipsum dolor sit], [Swordfish]
[Sour Priestess], [hendrerit nibh tempor], [Perch]
[Frozen Justice], [Interdum ex felis], [Swordfish]
It correctly prints the random data I put into the LV.
This will allow you to process the ListView Data in the BackGroundWorker but it wont really save any time, it just keeps the UI unlocked. The real problem is elsewhere, probably in the DB ops.

for loop : string & number without keep adding &

I'm learning for loop and I cannot get this problem fixed.
The problems are in the following codes.
dim rt as integer = 2
dim i As Integer = 0
dim currentpg as string = "http://homepg.com/"
For i = 0 To rt
currentpg = currentpg & "?pg=" & i
messagebox.show(currentpg)
next
'I hoped to get the following results
http://homepg.com/?pg=0
http://homepg.com/?pg=1
http://homepg.com/?pg=2
'but instead I'm getting this
http://homepg.com/?pg=0
http://homepg.com/?pg=0?pg=0
http://homepg.com/?pg=0?pg=0?pg=0
Please help me
Thank you.
You probably need something like this:
Dim basepg as string = "http://homepg.com/"
For i = 0 To rt
Dim currentpg As String = basepg & "?pg=" & i
messagebox.show(currentpg)
Next
Although a proper approach would be to accumulate results into a List(Of String), and then display in a messagebox once (or a textbox/file, if too many results). You don't want to bug user for every URL (what if there are 100 of them?). They would get tired of clicking OK.
First of all, you went wrong while copying the output of the buggy code. Here is the real one.
http://homepg.com/?pg=0
http://homepg.com/?pg=0?pg=1
http://homepg.com/?pg=0?pg=1?pg=2
It does not work because currentpg should be a constant but it is changed on each iteration.
Do not set, just get.
MessageBox.Show(currentpg & "?pg=" & i)
Or you can use another variable to make it more readable.
Dim newpg As String = currentpg & "?pg=" & i
MessageBox.Show(newpg)
Also, your code is inefficient. I suggest you to change it like this.
Dim iterations As Integer = 2
Dim prefix As String = "http://homepg.com/?pg="
For index As Integer = 0 To iterations
MessageBox.Show(prefix & index)
Next

check if a file exists and save a new file with an increment

So I know how to increment. I have the following code working:
Dim startFileName As String = StorageRoot & endFile
Dim endFileName As String = String.Empty
Dim Counter As Integer = 1
Do
Dim myFileInfo As New FileInfo(startFileName)
endFileName = myFileInfo.DirectoryName & IIf(Not myFileInfo.DirectoryName.EndsWith("\"), "\", String.Empty).ToString & _
Path.GetFileNameWithoutExtension(startFileName) & Counter & myFileInfo.Extension
Counter += 1
Loop Until Not IO.File.Exists(endFileName)
endFile = endFileName
This works. But here's my dilemma. Lets say the following files exist:
filename_v1.ext
filename_v2.ext
filename_v3.ext
filename_v4.ext
And then the user deletes one of them, lets say filename_v3.ext
On the next upload with my above logic, I need a way for it to make it v5 and not v3 again. The way it is now, it loops and stops after v2 and creates a v3 again.
Thanks for the help!
You can get an array of all files that match filename_v*.ext from Directory.GetFiles(path, searchPattern).
Dim files As String() = Directory.GetFiles("c:\SomePath", "filename_v*.ext")
Parse out the numbers after _v, order them, then take the highest + 1.

Append text to existing row in datatable

I'm trying to make a calendar in vb.net and I have come across this problem. I want to append some text into an existing datatable row. When I watch my debugger it says:"In order to evaluate an indexed property, the property must be qualified and the arguments must be explicitly supplied by the user.".
Dim aantalRijen As Integer = 1
For x = 0 To 6
Dim dttopdrachten As New DataTable
dttopdrachten = opdrachtendao.getOpdrachtenByDate(Today.AddDays(x))
If dttopdrachten.Rows.Count > aantalRijen Then
aantalRijen = dttopdrachten.Rows.Count
End If
Next
For z = 0 To aantalRijen - 1
Dim r As DataRow
r = dttAgenda.NewRow()
dttAgenda.Rows.InsertAt(r, z)
Next
For i = 0 To 6
Dim aantalItems As Integer = 0
Dim dttopdrachten As New DataTable
dttopdrachten = opdrachtendao.getOpdrachtenByDate(Today.AddDays(i))
aantalItems = dttopdrachten.Rows.Count
For j = 0 To aantalItems - 1
Dim info As String = dttopdrachten.Rows(j).Item(0).ToString & vbCrLf & dttopdrachten.Rows(j).Item(2).ToString & vbCrLf & dttopdrachten.Rows(j).Item(3).ToString & vbCrLf & dttopdrachten.Rows(j).Item(4).ToString & vbCrLf & dttopdrachten.Rows(j).Item(5).ToString & vbCrLf & dttopdrachten.Rows(j).Item(6).ToString
dttAgenda.Rows(j).Item(i) = info
Next
Next
dgvAgenda.DataSource = dttAgenda
In the code above, I first count how many rows I have to make. Afterwards I add the amount of rows to the datatable (columns are added before). Until here it works, but then when I keep debugging I get the error. I tried googling but nothing could help me so far.
Seem problem has been solved without changing anything. So if someone want to make a calendar. Here's the solution ;)

Visual Basic Loop and Display one line at a time

I'm using visual studios 2008, VB9 and I am trying to write an app that basically performs calculations on a set of data input by a user. During the calculations, I want to display the data at each step, and have it retained in the display area on the GUI (not overwritten by the next data being displayed).
For example:
UserInput = 1
Do
UserInput += 1
OutputLabel.Text = "UserInput " & UserInput
Loop Until UserInput = 5
and the output would look like
UserInput 1
UserInput 2
UserInput 3
UserInput 4
UserInput 5
I tried this, and other loop structures and can't seem to get things right. The actual app is a bit more sophisticated, but the example serves well for logical purposes.
Any tips are welcome, thanks!
This is the simple version:
Dim delimiter as String = ""
For UserInput As Integer = 1 To 5
OutputLabel.Text &= String.Format("{0}UserInput {1}", delimiter, UserInput)
delimiter = " "
Next
However, there are two problems with it and others like it (including every other answer given so far):
It creates a lot of extra strings
Since it's in a loop the label won't be able to process any paint events to update itself until you finish all of your processing.
So you may as well just do this:
Dim sb As New StringBuilder()
Dim delimiter As String = ""
For UserInput As Integer = 1 To 5
sb.AppendFormat("{0}UserInput {1}", delimiter, UserInput)
delimiter = " "
Next
OutputLabel.Text = sb.ToString()
And if you really want to have fun you can just do something like this (no loop required!):
OutputLabel.Text = Enumerable.Range(1, 5).Aggregate(Of String)("", Function(s, i) s & String.Format("UserInput {0} ", i))
You need to concatenate the value in OutputLabel.Text.
OutputLabel.Text &= "UserInput " & UserInput
You might also want to reset it before the loop: OutputLabel.Text = ""
If you need an iterated index you can try something like the following
For I As Integer = 1 To 5
If I > 1 Then OutputLabel.Text &= " "
OutputLabel.Text &= "UserInput " & I.ToString()
End For
If you have user inputs in a collection, you might better be served by using ForEach loop.
Do you need to do it in a GUI? If it is simply processing and putting out rows like that, maybe you should consider a console application, in which case it becomes REALLY easy, in simply calling
Console.WriteLine("my string")
All of these ways actually work really well but the one that fit my situation the best was this:
Do
Dim OutputString as String
Application.DoEvents() 'to make things paint actively
UserInput += 1
OutputString = String.Format("{0}", UserInput)
ListBox.Items.Add(OutputString)
Loop Until UserInput = 5
I changed things to a listbox but tried this same method with textboxes and labels, with some tweaks, they all worked very well. Thanks for all your help!
I'd use a more appropriate control, like richtextbox
Dim UserInput As Integer = 0
Const userDone As Integer = 5
RichTextBox1.Clear()
Do
RichTextBox1.AppendText(String.Format("User input {0:n0} ", UserInput))
RichTextBox1.AppendText(Environment.NewLine)
RichTextBox1.Refresh() 'the data at each step
UserInput += 1
Loop Until UserInput = userDone