Reputation: 73
I have two multiline textboxes; txtInputList and txtComplete. I can manually move a line from txtInputList to txtComplete while removing the line from txtInputList as the desired result. However, I am having difficulty in automating this for every line. Here is the manual way clicking the button for each line:
Private Sub btnProcessItems_Click(sender As Object, e As EventArgs) Handles btnProcessItems.Click
Dim strText() As String
strText = Split(txtInputList.Text, vbCrLf)
txtInputList.Text = String.Join(vbCrLf, strText, 1, strText.Length - 1)
txtComplete.AppendText(strText(0) + vbCrLf)
End Sub
That works as desired. I've tried a For-loop, but I can't get it to work.
Private Sub btnProcessItems_Click(sender As Object, e As EventArgs) Handles btnProcessItems.Click
Dim strText() As String
strText = Split(txtInputList.Text, vbCrLf)
For x As Integer = 0 to strText.Length
txtInputList.Text = String.Join(vbCrLf, strText, 1, strText.Length - 1)
txtComplete.AppendText(strText(0) + vbCrLf)
Next
End Sub
Can someone please help? Thank you!
Upvotes: 0
Views: 67
Reputation: 39122
Totally agree with djv's answer, but here's one way to do it directly with the UI:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If TextBox1.Text.Trim.Length = 0 Then
Exit Sub
End If
Button1.Enabled = False
TextBox1.Enabled = False
TextBox2.Enabled = False
TextBox2.Clear()
Dim lines As New List(Of String)(TextBox1.Lines)
Dim processed As New List(Of String)
While (lines.Count > 0)
Dim current As String = lines(0)
lines.RemoveAt(0)
TextBox1.Lines = lines.ToArray
' ... do something with "current" ...
Label1.Text = "Processing: " & current
Await Task.Delay(2000)
processed.Add(current)
TextBox2.Lines = processed.ToArray
End While
Label1.Text = ""
TextBox1.Enabled = True
TextBox2.Enabled = True
Button1.Enabled = True
End Sub
Here it is in action:
Upvotes: 0
Reputation: 15774
Don't keep your data on your UI. Use a data structure to keep your data so you can operate on it directly (off the UI thread) then update the UI with the state of your data. If your data is just a list of strings then use List(Of String)
or if it is more than just strings, use a List(Of someClass)
.
My answer will fix a number of issues for you.
First, a class to hold the data. You have the option for a nice name for display, and a Url or whatever other property you want to use in your processor
Public Class Data
Public Property Name As String
Public Property Url As String
Public Sub New(name As String)
Me.Name = name
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Make lists of input items and complete items, and I will initialize inputs with 10 items, with letters A ... J. Also define a method to put both lists into your TextBoxes
Private inputs As List(Of Data)
Private completes As List(Of Data)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' initialize our fake data
inputs = Enumerable.Range(65, 10).Select(Function(i) New Data(New String({Chr(i)}))).ToList()
completes = New List(Of Data)()
bindTextBoxes()
End Sub
Private Sub bindTextBoxes()
txtInputList.Text = String.Join(Environment.NewLine, inputs)
txtComplete.Text = String.Join(Environment.NewLine, completes)
End Sub
Add an Async button handler to process all items, and Task function to process each item. The button handler doesn't process anything, rather it's handled in the Awaited task. After each item is handled, you rebind the TextBoxes to update the UI.
Private Async Sub btnProcessItems_Click(sender As Object, e As EventArgs) Handles btnProcessItems.Click
While inputs.Any()
Await processFirstItem()
bindTextBoxes()
End While
End Sub
Private Function processFirstItem() As Task
Return Task.Run(
Sub()
Dim item = inputs.First()
inputs.RemoveAt(0)
processItem(item)
completes.Add(item)
End Sub)
End Function
Private Sub processItem(item As Data)
' do whatever you need to do on the item, emulate a delay with thread sleep
Threading.Thread.Sleep(250) ' remove this in production
End Sub
You may notice if you try this code that it runs off the UI so your app will run smoothly. You are just acting on a data structure instead of the UI. This is one good way to do what you are trying to do.
If your processing can be done in parallel, then you should look into Task Parallel Library, and your work will probably be performed much faster depending on the resources being used.
Upvotes: 1
Reputation: 11773
Try this, you'll need to change the names of the textboxes.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sb As New System.Text.StringBuilder
For Each line As String In TextBox1.Lines
sb.AppendLine(line)
Next
TextBox1.Clear()
TextBox2.Text = sb.ToString
End Sub
Upvotes: 0